Portable way of testing if a function exist

M

mathieu

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 */
 
N

nicolas.sitbon

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.
 
E

Eric Sosman

mathieu said:
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.
 
M

mathieu

mathieu said:
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
 
D

David Thompson

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.
 
K

Keith Thompson

David Thompson said:
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.
 
D

David Thompson

David Thompson said:
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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top