Given the following code written according to the C99 standard:
#define LOW 1
#define MEDIUM 2
#define HIGH 3
#define LOGGING_LEVEL HIGH
#if LOGGING_LEVEL >= MEDIUM
#define LOG_MEDIUM(message) printf(message)
#else
#define LOG_MEDIUM(message) ((void)0)
#endif
void load_configuration() {
//...
LOG_MEDIUM("Configuration loaded\n");
}
what's the purpose of ((void)0) I searched the web a lot but nothing found regarding this.
Plus, why didn't we wrote ; after using printf(message)
The void-cast fixes a compiler warning. Here's an analogous testcase:
int main(void)
{
0; // generates "foo.c:3:2: warning: statement with no effect"
(void)0;
return 0;
}
and (using a script to add gcc's warning flags) you see a warning for the line without a cast:
$ gcc-stricter -c foo.c
foo.c: In function ‘main’:
foo.c:3:2: warning: statement with no effect [-Wunused-value]
0;
^
The extra parentheses and lack of semicolon allow the macro's result to be used interchangeably with the printf.
Main idea is to exclude all LOG_MEDIUM if the criteria was not meet.
After compilation those calls will not affect functionality.
Related
There are a ton of questions about suppressing "variable set but not used" warnings, but I haven't found one that addresses my very specific problem, which is a debugging macro defined as follows:
#ifdef DEBUG
# define dbg_printf(...) ((void)printf(__VA_ARGS__))
#else
# define dbg_printf(...) ((void)( /* ??? */ ))
#endif
A variable that is set unconditionally, and then used only as one of the arguments to dbg_printf, should not trigger "variable set but not used" warnings, whether or not DEBUG is defined. It should not be necessary to annotate such variables at the point of definition. For example, this should be warning-free:
struct Thing { int value; struct Thing *next; };
struct Thing *find_first_match(int n, struct Thing *list)
{
struct Thing *p;
int searched = 0;
for (p = list; p; p = p->next) {
searched++;
if (p->value == n) break;
}
dbg_printf("%s: %s after scanning %d entries\n",
__func__, p ? "found" : "not found", searched);
return p;
}
I have tried a couple things in place of the /* ??? */, but nothing I have tried so far has worked without undesirable side effects:
# define dbg_printf(...) ((void)(0 && (__VA_ARGS__)))
Causes some versions of clang to complain about unused values, e.g.
void foo(void) {
dbg_printf("%d\n", 23);
}
⟶
test.c:4:14: warning: expression result unused [-Wunused-value]
dbg_printf("%d\n", 23);
^~~~~~
# define dbg_printf(...) ((void)(sizeof(__VA_ARGS__)))
Causes some versions of clang to complain about misuse of sizeof, e.g. same test case
test.c:4:14: warning: sizeof on pointer operation will return size of 'const char *'
instead of 'const char [4]' [-Wsizeof-array-decay]
dbg_printf("%d\n", 23);
^~~~~~
[Edited to add:] An inline variadic function that does nothing, instead of a macro, e.g.
static inline void dbg_printf(const char *msg, ...) {
(void)msg;
}
is no good because its arguments will still be evaluated for their
side effects, and the offending code base has lots of instances of
stuff like
// code that mutates a global data structure, and then ...
dbg_printf("validation status after %s: %s\n", __func__,
expensive_global_data_structure_validation());
Please suggest a construct that can be used in place of the /* ??? */ that will suppress "variable set but not used" warnings without introducing other spurious diagnostics in their place. If this can be done with strictly conforming C2011 code, that is preferable. Compiler extensions are acceptable if and only if they work correctly on all four of:
gcc 4.8
gcc 9.x
clang 7.0
clang 10.0
Yes, we are stuck using old compilers for good reasons, or at least reasons which nobody has the spare cycles to overcome.
I use this trick to disable such warnings:
#ifdef DEBUG
# define dbg_printf(...) ((void)printf(__VA_ARGS__))
#else
# define dbg_printf(...) do { if ((0)) (void)printf(__VA_ARGS__); } while (0)
#endif
This macro generates no code in optimized builds but does not complain about variables initialized and only used inside the argument list.
I use do { ... } while (0) to encapsulate the if statement in a block so the macro can be used as a regular function call in a context where a single statement is needed such as this:
if (something_went_wrong())
dbg_printf("something went wrong\n");
else
keep_going();
I write the test if ((0)) with a double pair or parentheses to avoid a warning on constant expression always false and/or unreachable code. clang would issue a warning about unreachable code with -Weverything (which includes -Wunreachable-code). They recommend the use of redundant parentheses to silence this warning in contexts where it is the programmer's intent.
do { } while (0) does not trigger this warning because it is a classic idiom to group statements as a single statement.
The {} are redundant to, the macro could be simplified as:
#define dbg_printf(...) do if((0))(void)printf(__VA_ARGS__);while(0)
The same goal can be reached with a simpler logical expression, that may or may not trigger other compiler warnings:
#define dbg_printf(...) ((void)(((0)) && printf(__VA_ARGS__)))
This will work:
#ifdef DEBUG
# define dbg_printf(...) ((void)printf(__VA_ARGS__))
#else
# define dbg_printf(...) ((void)(0 && printf(__VA_ARGS__)))
#endif
As the right-hand side of the && operator won't be evaluated.
Alternately:
#ifdef DEBUG
# undef DEBUG
# define DEBUG 1
#else
# define DEBUG 0
#endif
Then:
#define dbg_printf(...) ((void)(DEBUG && printf(__VA_ARGS__)))
That way you have if multiple such definitions depending on DEBUG you only need a single #ifdef.
Based on this question How to catch empty defined macro with gcc? I have another problem. How to catch undefined macro in preprocessor #if condition? Example code:
#include <stdio.h>
int main()
{
#if ENABLE_SOMETHING == 1
... do something ..
#endif
return 0;
}
Is there a way to catch error/warning when ENABLE_SOMETHING is not set using gcc compiler(maybe some flag)? Or maybe there are external tools which I can use?
I know than i can write something like this :
#ifndef ENABLE_SOMETHING
#error "ENABLE_SOMETHING undefined!"
#endif
But I have a huge amount of different defines(ENABLE_STH1, ENABLE_STH2, ENALBE_STH3 ... etc.) in code and i don't want to fix this manually. I'm looking for some automatic solution for our project.
Is there a way to catch error/warning when ENABLE_SOMETHING is not set
using gcc compiler(maybe some flag)?
With GCC you can use the -Wundef flag.
From the official documentation
-Wundef
Warn if an undefined identifier is evaluated in an #if directive. Such identifiers are replaced with zero.
EDIT:
For example, this C-code:
#include <stdio.h>
int main(void)
{
#if UNDEFINED_MACRO
printf("hi mum!\n");
#endif
return 0;
}
... compiled with GCC and the -Wundef flag yields this:
$ gcc undef.c -Wundef
undef.c: In function 'main':
undef.c:5:5: warning: "UNDEFINED_MACRO" is not defined [-Wundef]
#if UNDEFINED_MACRO
^
Let's assume you have this code and it compiles, but you don't know if MAX_N_LENGTH is a macro, or if it's something else:
int main()
{
int a = MAX_N_LENGTH; // MAX_N_LENGTH could also be an int declared somewhere else
return 0;
}
You can check whether it actually is a macro like this:
#ifdef MAX_N_LENGTH
printf("MAX_N_LENGTH is a macro.\n");
#else
printf("MAX_N_LENGTH is NOT macro.\n");
#endif // MAX_N_LENGTH
Of course, if that ever is an issue, I'd rethink my naming conventions.
You could try something like the following:
#ifndef MAX_N_LENGTH
#warning "MAX_N_LENGTH is undefined"
int array[16];
#else
int array[MAX_N_LENGTH + 1];
#endif
You can test if a macro is defined in a #if preprocessor expression with defined(ENABLE_SOMETHING):
#if !defined(ENABLE_SOMETHING)
#error ENABLE_SOMETHING is not defined
#endif
You can handle macros with an empty definition this way:
#if ENABLE_SOMETHING + 0 == 1
/* ENABLE_SOMETHING is defined and not 0 or empty */
#endif
Given the following code in a project I'm working on:
/* Pre-definitions in a pre-definitions file to be included in the project */
#ifdef WIN32
#define __FUNCNAME__ __FUNCTION__
#else
#define __FUNCNAME__ __func__
#endif
/* My definitions */
#define MAC() \
MAC1()
#define MAC1() \
myPrintFunction(__FUNCNAME__)
/* My print function */
void myPrintFunction(const char * functionName)
{
printf("\n func name: %s \n",functionName);
}
/* Macro usage example function */
void myFunction()
{
if (some_condition)
{
MAC();
}
}
The function name is presented as an empty string.
Any idea why, and how can I fix it?
Code compiled and tested on Linux machine, using GCC compiler.
Use __func__ out of the box. It's been part of the C standard since C99. Change your compiler settings to use at least that standard.
Note that __func__ is not a macro but a predefined identifier which takes the form such that writing it anywhere within a function body is exactly equivalent to using it at that point, having first written
static const char __func__[] = "function-name";
just after the opening brace of a function body.
Formally the behaviour of your current code is undefined. Any symbol containing two consecutive underscores is reserved by the system. (That includes macro names, function names, and variable names.)
Your code as presented gives the expected result (once I'd added the necessary includes and main):
#include <stdio.h>
#ifdef WIN32
#define __FUNCNAME__ __FUNCTION__
#else
#define __FUNCNAME__ __func__
#endif
/* My definitions */
#define MAC() \
MAC1()
#define MAC1() \
myPrintFunction(__FUNCNAME__)
void myPrintFunction(const char * functionName)
{
printf("\n func name: %s \n",functionName);
}
int main()
{
MAC();
}
I compiled this using gcc -std=c11 -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds with no warnings.
You should really post a complete (but minimal) example that actually compiles, along with the compiler flags you used, as something must certainly be different to explain the symptoms you describe.
Also, when writing statements as macros, you may find it helpful to use the do {...} while (0) idiom to avoid unexpected expansions changing the control flow.
I have some macros that are defined based on compiler flags. I'm trying to decide whether I would rather have the macro defined as (void)0 or have it undefined and cause a compile time error.
i.e.
#ifdef DEBUG
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...) (void)0
#endif
int main(void) {
...
PRINTF("something");
...
}
vs.
#ifdef DEBUG
#define PRINTF(...) printf(__VA_ARGS__)
#endif
int main(void) {
...
#ifdef DEBUG
PRINTF("something");
#endif
...
}
I'm not sure which technique I prefer. On one hand wrapping every PRINTF statement with #ifdef's would be ugly. On the other hand it would be nice to know at compile time if I've called a function that doesn't really work in the context.
I think the deciding factor will be whether or not having the (void)0 macros is going to affect the size of the executable.
When the code is compiled, what happens to the (void)0's? If PRINTF is defined as (void)0, does that mean the executable is going to contain some sort of (void)0 instruction or will it be completely ignored?
(void) 0;
is an expression statement with no side-effect. Any sane implementation will optimize this statement out (what else an implementation could do with such a statement?).
Having (void) 0 as a macro definition is endorsed by the C Standard as it appears in (C11) 7.2p1 for assert macro definition if NDEBUG is defined:
#define assert(ignore) ((void)0)
Note that defining:
#define PRINTF(...) (void)0
instead of
#define PRINTF(...)
has an advantage. In the first case, you have an expression (like a function that returns no value) and so it is usable for example in a comma expression or in a conditional expression.
For example:
// Comma expression
printf("test"), PRINTF("Hi Dennis");
// Conditional expression
test-expr ? perror("Hello") : PRINTF("world");
This two expression statements are only valid with the former PRINTF definition (with (void) 0).
It'll be completely ignored, you can confirm this by looking at the assembly output (gcc -S will generate file.s, the asm output), compare with and without the (void)0 line and see that it is completely the same.
A half way decent compiler will optimise away dead (unreachable) code, so you can:
#ifdef DEBUG
#define PRINTF(...) if (1) { printf(__VA_ARGS__) ; }
#else
#define PRINTF(...) if (0) { printf(__VA_ARGS__) ; }
#endif
which has the big advantage of allowing the compiler to check the debug code, no matter whether you are working with/without your DEBUG turned on -- which reduces the risk of ending up with painful teeth marks in your backside.
I have a logging macro which in release mode becomes:
#define LOG (void)
So statement
LOG("foobar %d", 0xbabecafe);
is expanded to
(void)("foobar %d", 0xbabecafe);
The problem is that the last expression produces an warning under gcc:
warning: left-hand operand of comma expression has no effect [-Wunused-value]
How can I change the logging macro such that no warning is issued? (Note, that I don't want to add compiling flag -Wunused-value).
EDIT I see already a couple of answers involving (...). The same file is compiled under Minix which doesn't support variadic macros. The best would be to have a C89 conforming solution. While your answer is correct (and I upvoted it), it is my fault that I didn't include this small detail.
I think the old school way of dealing with this is to take advantage of double parens. Something like this:
LOG(("message: %d", 10));
Then for your macro, you define it like this:
#define LOG(x) printf x
or
#define LOG(x) (void)0
Because of the double parens, the pre-processor treats the whole inner paren as a single parameter. This at least used to work in visual studio.
EDIT: I did a quick test, it works with gcc with -ansi, so it should be good:
gcc -DNDEBUG -ansi -pedantic -W -Wall test.c -o test
#include <stdio.h>
#ifdef NDEBUG
#define LOG(x) printf x
#else
#define LOG(x) (void)0
#endif
int main() {
LOG(("message: %d\n", 10));
return 0;
}
The easiest should be
#define LOG(...) (void)0
(gcc supports the C99 variadic macros and most other compilers also do these days) That will discard the arguments list, which has two advantages:
it does not create statements with no effect and
the arguments are not evaluated at all (if you call non-inline functions in the argument list, in your version the compiler can't eliminate them, while with the variadic macro, the compiler won't see them at all.
#define LOG(...) seems to do the trick.
For your problems with a non-conforming C implementation (not even C89?) you could do something like
static void LOG(char *format, ...) { /* empty */ }
even a completely dumb compiler should be able to optimize that out.
I've used
#define LOG( t) t
for the development version and
#define LOG( t)
for the release version, with a typical use being
LOG( printf( "here\n"));