Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function macro that evaluates to zero and can be used as a statement

We have a function macro #define FOO(arg) foo(arg) with int foo(const char* bar);. When NDEBUG is defined FOO is defined as #define FOO(arg) 0, however this causes many compiler warnings because in many cases FOO's return value is not used. The solution should work with with ANSI C compilers and cause no warnings. I've tried:

(void)0: can't be assigend to variable

static int foo(const char* bar) { return 0; } : causes unused static function warning in some modules

static inline int foo(const char* bar) { return 0; } : only works with C99 compilers

Thanks for your help!

edit1: It's somewhat like a trace macro and used all over the project. Mostly it's just used as a statement like FOO("function x called");, but in a few cases I saw if (FOO("condition a")) { /* some more debug output */ }. With NDEBUG defined and optimization enabled nothing should be left of FOO. I didn't come up with this, but I have to clean up this mess :).

edit2: I should add that for gcc release builds these flags are used: -O3 -Wall -ansi

edit3: For now I'm going with __inline int dummy() { return 0; }. __inline works with both VisualC and GCC in ansi mode.

like image 932
maep Avatar asked Apr 17 '12 11:04

maep


3 Answers

I guess it's a little bit compiler dependent but this should work:

#ifndef NDEBUG
    #define FOO(arg) foo(arg)
#else
    #define FOO(arg) ((int)0)
#endif

It prevents the "expression has no effect" warning, it does nothing and its value when used is still 0.

EDITED
It seems it's something not so portable so (now) you have these conditions:

  • (0) or ((int)0) work at least on VC 2010.
  • __noop should work on any version of VC after 2003.

VC6 is not a problem because it doesn't emit the C4555 warning at all. For other compilers you may use:

  • ((void)0, 0) It may work on a lot of compilers (maybe it's the more portable one?).
  • inline int foo(const char* bar) { return 0; } works with any other C99 compiler (as you wrote you may need to declare it as static on gcc).

For any other prehistoric C compiler use the solution pointed by @Jobs: abs(0)

like image 139
Adriano Repetti Avatar answered Oct 15 '22 05:10

Adriano Repetti


What you could do to prevent the warning is the following:

#ifndef NDEBUG
    #define FOO(arg) foo(arg)
#else
    #define FOO(arg) abs(0)
#endif

I'm not saying this is ideal (you'd have to make sure stdlib.h is included everywhere, for example) but it does prevent the warning.

like image 36
mtvec Avatar answered Oct 15 '22 07:10

mtvec


I'd do something that is dependent on the C version. In the header file:

#if __STDC_VERSION__ > 199900L
inline int foo(const char* bar) { return 0; }
#else
int foo(const char* bar);
#endif

in one compilation unit

#if __STDC_VERSION__ < 199900L
int foo(const char* bar) { return 0; }
#else
int foo(const char* bar);
#endif

or use for the oldish C version something like Job's answer, that is a function that is certain to be optimized out but that doesn't produce the warning.

like image 35
Jens Gustedt Avatar answered Oct 15 '22 05:10

Jens Gustedt