Portable way of testing if a function exist

Discussion in 'C Programming' started by mathieu, Dec 6, 2008.

  1. mathieu

    mathieu Guest

    Hi there,

    I am using the following piece of code (*) to determine whether or
    not a particular function exist. It is working fine most of the time,
    but I recently got a case where it shows limitation: builtins
    functions. For instance compiling it with a recent gcc version leads
    to:

    $ gcc -DCHECK_FUNCTION_EXISTS=strncasecmp -o CheckFunctionExists.o -
    c CheckFunctionExists.c
    CheckFunctionExists.c:3: warning: conflicting types for built-in
    function ‘strncasecmp’

    Any suggestion on a better way to do that ?

    Thanks!
    -Mathieu

    (*)
    #ifdef CHECK_FUNCTION_EXISTS

    char CHECK_FUNCTION_EXISTS();
    #ifdef __CLASSIC_C__
    int main(){
    int ac;
    char*av[];
    #else
    int main(int ac, char*av[]){
    #endif
    CHECK_FUNCTION_EXISTS();
    if(ac > 1000)
    {
    return *av[0];
    }
    return 0;
    }

    #else /* CHECK_FUNCTION_EXISTS */

    # error "CHECK_FUNCTION_EXISTS has to specify the function"

    #endif /* CHECK_FUNCTION_EXISTS */
     
    mathieu, Dec 6, 2008
    #1
    1. Advertising

  2. mathieu

    Guest

    On 6 déc, 10:47, mathieu <> wrote:
    > Hi there,
    >
    >   I am using the following piece of code (*) to determine whether or
    > not a particular function exist. It is working fine most of the time,
    > but I recently got a case where it shows limitation: builtins
    > functions. For instance compiling it with a recent gcc version leads
    > to:
    >
    > $ gcc  -DCHECK_FUNCTION_EXISTS=strncasecmp -o CheckFunctionExists.o   -
    > c CheckFunctionExists.c
    > CheckFunctionExists.c:3: warning: conflicting types for built-in
    > function ‘strncasecmp’
    >
    > Any suggestion on a better way to do that ?
    >
    > Thanks!
    > -Mathieu
    >
    > (*)
    > #ifdef CHECK_FUNCTION_EXISTS
    >
    > char CHECK_FUNCTION_EXISTS();
    > #ifdef __CLASSIC_C__
    > int main(){
    >   int ac;
    >   char*av[];
    > #else
    > int main(int ac, char*av[]){
    > #endif
    >   CHECK_FUNCTION_EXISTS();
    >   if(ac > 1000)
    >     {
    >     return *av[0];
    >     }
    >   return 0;
    >
    > }
    >
    > #else  /* CHECK_FUNCTION_EXISTS */
    >
    > #  error "CHECK_FUNCTION_EXISTS has to specify the function"
    >
    > #endif /* CHECK_FUNCTION_EXISTS */


    try with -fno-builtin.
     
    , Dec 6, 2008
    #2
    1. Advertising

  3. mathieu

    Eric Sosman Guest

    mathieu wrote:
    > Hi there,
    >
    > I am using the following piece of code (*) to determine whether or
    > not a particular function exist. It is working fine most of the time,
    > but I recently got a case where it shows limitation: builtins
    > functions. For instance compiling it with a recent gcc version leads
    > to:
    >
    > $ gcc -DCHECK_FUNCTION_EXISTS=strncasecmp -o CheckFunctionExists.o -
    > c CheckFunctionExists.c
    > CheckFunctionExists.c:3: warning: conflicting types for built-in
    > function ‘strncasecmp’
    >
    > Any suggestion on a better way to do that ?


    Yes: Read the documentation that comes with your C
    implementation. "That's not automated," you may object,
    but neither is the process of compiling, linking, and
    looking for error messages. (If any; see below.)

    > #ifdef CHECK_FUNCTION_EXISTS
    >
    > char CHECK_FUNCTION_EXISTS();


    If the function *does* exist, and if this declaration
    doesn't match the function's actual type, the behavior is
    undefined. You may or may not get an error message; the
    message may even amount to "no such function" even if a
    function by that name does in fact exist. If you get no
    error message you can conclude that the function exists,
    but the presence of a message is not foolproof evidence
    that the function is absent.

    > #ifdef __CLASSIC_C__


    Bad choice of macro name: All identifiers beginning
    with two underscores are reserved.

    > int main(){
    > int ac;
    > char*av[];


    Missing a { here.

    > #else
    > int main(int ac, char*av[]){
    > #endif
    > CHECK_FUNCTION_EXISTS();
    > if(ac > 1000)
    > {
    > return *av[0];
    > }
    > return 0;
    > }
    >
    > #else /* CHECK_FUNCTION_EXISTS */
    >
    > # error "CHECK_FUNCTION_EXISTS has to specify the function"


    The #error directive wasn't standardized until the ANSI
    document was adopted in 1989, so if you still want to cater
    to "classic C" you should probably avoid using it.

    > #endif /* CHECK_FUNCTION_EXISTS */


    Again: RTFM. It's a much better way, and will tell you
    useful things like what the rewindWidget() function does,
    what arguments it takes, and what special compiler flags
    you need to use to get at it.

    --
    Eric Sosman
    lid
     
    Eric Sosman, Dec 6, 2008
    #3
  4. mathieu

    mathieu Guest

    On Dec 6, 3:06 pm, Eric Sosman <> wrote:
    > mathieu wrote:
    > > Hi there,

    >
    > >   I am using the following piece of code (*) to determine whether or
    > > not a particular function exist. It is working fine most of the time,
    > > but I recently got a case where it shows limitation: builtins
    > > functions. For instance compiling it with a recent gcc version leads
    > > to:

    >
    > > $ gcc  -DCHECK_FUNCTION_EXISTS=strncasecmp -o CheckFunctionExists.o   -
    > > c CheckFunctionExists.c
    > > CheckFunctionExists.c:3: warning: conflicting types for built-in
    > > function ‘strncasecmp’

    >
    > > Any suggestion on a better way to do that ?

    >
    >      Yes: Read the documentation that comes with your C
    > implementation.  "That's not automated," you may object,
    > but neither is the process of compiling, linking, and
    > looking for error messages.  (If any; see below.)
    >
    > > #ifdef CHECK_FUNCTION_EXISTS

    >
    > > char CHECK_FUNCTION_EXISTS();

    >
    >      If the function *does* exist, and if this declaration
    > doesn't match the function's actual type, the behavior is
    > undefined.  You may or may not get an error message; the
    > message may even amount to "no such function" even if a
    > function by that name does in fact exist.  If you get no
    > error message you can conclude that the function exists,
    > but the presence of a message is not foolproof evidence
    > that the function is absent.
    >
    > > #ifdef __CLASSIC_C__

    >
    >      Bad choice of macro name: All identifiers beginning
    > with two underscores are reserved.
    >
    > > int main(){
    > >   int ac;
    > >   char*av[];

    >
    >      Missing a { here.
    >
    > > #else
    > > int main(int ac, char*av[]){
    > > #endif
    > >   CHECK_FUNCTION_EXISTS();
    > >   if(ac > 1000)
    > >     {
    > >     return *av[0];
    > >     }
    > >   return 0;
    > > }

    >
    > > #else  /* CHECK_FUNCTION_EXISTS */

    >
    > > #  error "CHECK_FUNCTION_EXISTS has to specify the function"

    >
    >      The #error directive wasn't standardized until the ANSI
    > document was adopted in 1989, so if you still want to cater
    > to "classic C" you should probably avoid using it.
    >
    > > #endif /* CHECK_FUNCTION_EXISTS */

    >
    >      Again: RTFM.  It's a much better way, and will tell you
    > useful things like what the rewindWidget() function does,
    > what arguments it takes, and what special compiler flags
    > you need to use to get at it.


    I said "portable", I am targeting unknown system with unknown
    compiler. Please Read the Fine Subject Line.

    This is used internally in cmake and works everywhere, except in the
    very particular case of -Werror and recent gcc version with builtins
    functions.

    -M
     
    mathieu, Dec 7, 2008
    #4
  5. On Sat, 6 Dec 2008 01:47:56 -0800 (PST), mathieu
    <> wrote:

    > char CHECK_FUNCTION_EXISTS();
    > #ifdef __CLASSIC_C__


    As already said, that's a poor choice of macroname. Why not just do
    #ifndef __STDC__ ? That's guaranteed to work for conforming
    implementations, and while the standard can't actually apply to
    nonconforming ones, if there had been any that had a problem with it
    there would already have been a big stink 19 years ago.

    > int main(){
    > int ac;
    > char*av[];


    This was never valid, even _before_ K&R1. You need
    int main (ac,av) int ac; char *av[]; /* or **av */ {

    > #else
    > int main(int ac, char*av[]){
    > #endif
    > CHECK_FUNCTION_EXISTS();


    Calling a function that actually takes parameters (which your example
    of strncasecmp does) without giving it the arguments is Undefined
    Behavior and is likely to screw up badly on quite a few systems.
    Declaring a function with the wrong return type, as you did and was
    diagnosed, and calling it and ignoring the putative result, is also
    Undefined Behavior but in practice is much less likely to screw up.

    Unless you're only compiling and not running this code. But that's not
    a sufficient check; I know at least one system that will successfully
    compile (and link) a reference to an unavailable function, and fail
    only when run. (Which is permitted by the C standards.)

    > if(ac > 1000)
    > {
    > return *av[0];
    > }


    This is just silly. No one should want to run this program with 1001
    arguments, not even in an automated environment. If you actually want
    to have some nontrivial (i.e. testable) functionality, I would suggest
    something more like
    if( ac >= 2 ) return atoi (av[1]);
    /* yes atoi() isn't the safest, but here that's lost in the weeds */
    or even
    if( ac >= 2 && isdigit((uchar)av[1][0]) ) return av[1][0] - '0';

    OTOH if you're actually hoping for reliable evidence of the screwup(s)
    mentioned above, you're in fantasyland.

    > return 0;
    > }


    You're probably better off #include'ing all the standard headers that
    appear to exist (as files) on your system, including standards other
    than C e.g. POSIX if you want, turning on all the extension macros you
    know about (which generally do no harm if you specify them when they
    aren't applicable), and trying to compile a _type-valid_ call to the
    desired function. This still isn't 100%, but it's closer.

    But please have some way for a (competent) human to override or alter
    the results. Hopefully it won't be needed often, but if it's needed
    and not possible you will make some users very unhappy.
     
    David Thompson, Dec 15, 2008
    #5
  6. David Thompson <> writes:
    > On Sat, 6 Dec 2008 01:47:56 -0800 (PST), mathieu
    > <> wrote:
    >> char CHECK_FUNCTION_EXISTS();
    >> #ifdef __CLASSIC_C__

    >
    > As already said, that's a poor choice of macroname. Why not just do
    > #ifndef __STDC__ ? That's guaranteed to work for conforming
    > implementations, and while the standard can't actually apply to
    > nonconforming ones, if there had been any that had a problem with it
    > there would already have been a big stink 19 years ago.

    [...]

    I seem to recall that some pre-conforming implementations defined
    __STDC__ as 0.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Dec 15, 2008
    #6
  7. On Mon, 15 Dec 2008 08:18:03 -0800, Keith Thompson <>
    wrote:

    > David Thompson <> writes:
    > > On Sat, 6 Dec 2008 01:47:56 -0800 (PST), mathieu
    > > <> wrote:
    > >> char CHECK_FUNCTION_EXISTS();
    > >> #ifdef __CLASSIC_C__

    > >
    > > As already said, that's a poor choice of macroname. Why not just do
    > > #ifndef __STDC__ ? That's guaranteed to work for conforming
    > > implementations, and while the standard can't actually apply to
    > > nonconforming ones, if there had been any that had a problem with it
    > > there would already have been a big stink 19 years ago.

    > [...]
    >
    > I seem to recall that some pre-conforming implementations defined
    > __STDC__ as 0.


    Good point. I don't recall if pre/nonstd preprocessors did unknown
    pp-id is zero, which would allow #if; probably not. Oh well.
     
    David Thompson, Dec 29, 2008
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Eli Bendersky
    Replies:
    1
    Views:
    1,171
    Mike Treseler
    Mar 1, 2006
  2. Y.S.
    Replies:
    3
    Views:
    1,026
    strajan
    Sep 17, 2003
  3. Brian van den Broek
    Replies:
    3
    Views:
    849
    Jeremy Bowers
    Apr 3, 2005
  4. Brian van den Broek
    Replies:
    2
    Views:
    394
    Brian van den Broek
    Apr 5, 2005
  5. Replies:
    7
    Views:
    921
Loading...

Share This Page