I have the following code, and while compiling it with gcc-4.6 I get warning:
warning: variable ‘status’ set but not used [-Wunused-but-set-variable]
#if defined (_DEBUG_)
#define ASSERT assert
#else /* _DEBUG_ */
#define ASSERT( __exp__ )
#endif
static inline void cl_plock(cl_plock_t * const p_lock)
{
status_t status;
ASSERT(p_lock);
ASSERT(p_lock->state == INITIALIZED);
status = pthread_rwlock_unlock(&p_lock->lock);
ASSERT(status == 0);
}
When _DEBUG_
flag isn't set I get the warning.
Any ideas how can I workaround this warning?
You can change your ASSERT macro to:
#if defined (_DEBUG_)
#define ASSERT assert
#else /* _DEBUG_ */
#define ASSERT( exp ) ((void)(exp))
#endif
If the expression has no sideeffects, then it should still be optimised out, but it should also suppress the warning (if the expression does have side-effects, then you would get different results in debug and non-debug builds, which you don't want either!).
The compiler option to turn off unused variable warnings is -Wno-unused.
To get the same effect on a more granular level you can use diagnostic pragmas like this:
int main()
{
#pragma GCC diagnostic ignored "-Wunused-variable"
int a;
#pragma GCC diagnostic pop
// -Wunused-variable is on again
return 0;
}
This is, of course, not portable but you can use something similar for VS.
You could surround the variable declaration of status with a #ifdef clause.
#ifdef _DEBUG_
status_t status
#endif
EDIT: You have to surround the call also:
#ifdef _DEBUG_
status = pthread_rwlock_unlock(&p_lock->lock);
#else
pthread_rwlock_unlock(&p_lock->lock);
#endif
or you can switch off the error message.
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
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
I'm working on some C code that does lot's of error reporting and logging when a DEBUG flag is set, which sometimes produces unused variable warnings when compiling with the DEBUG flag not set.
#ifdef DEBUG
#define CHECK(expr) foo(expr)
#else
#define CHECK(expr)
#endif /* DEBUG */
int x = bar(a, b, c); /* bar has to be called for both DEBUG begin defined and undefined */
CHECK(x == SOME_VALUE); /* Produces an "unused variable" warning if DEBUG is undefined
Edit: Just a little reminder (not sure if it is of any consequence): the argument for the CHECK macro is an expression, not a single variable.
For this pattern, what is the best way to get rid of the unused variable warning?
What I tried/though of:
#ifdef DEBUG
int x = bar(a, b, c);
#else
bar(a, b, c);
#endif
CHECK(x == SOME_VALUE);
and then, to avoid writing the call to bar (which is more complicated in the actual call) twice:
#ifdef DEBUG
int x =
#endif
bar(a, b, c);
CHECK(x == SOME_VALUE);
However, I feel like this is not exactly a clean and readable solution. Is there a better way? Note that for performance reasons the CHECK(expr) macro should not produce any code if DEBUG is undefined (EDIT: and thus, expr should not be evaluated).
Is there a more elegant way than the one I outlined above?
#ifdef DEBUG
#define CHECK(x) x
#else
#define CHECK(x) ((void)sizeof((void)(x),0))
#endif
I think this addresses all of the possible issues :
sizeof ensures that the expression is not evaluated at all, so its side-effects don't happen. That is to be consistent with the usual behaviour of debug-only constructs, such as assert.
((x), 0) uses the comma operator to swallow the actual type of (x). This is to prevent VLAs from triggering evaluation.
(void) explicitly ignores the result of (x) and sizeof so no "unused value" warning appears.
If I understood your question correctly, you can do something like
#ifdef DEBUG
.
.
#else
#define CHECK(expr) ((void)(expr))
#endif /* DEBUG */
to get rid of the warning.
With this solution there is no need for an intermediate variable.
#define DEBUG
#define DOCHECK(a) printf("DOCHECK %d\n", a)
#ifndef DEBUG
#define CHECK(a, b) a
#else
#define CHECK(a, b) do {int x = a; DOCHECK(x == b);} while (0)
#endif
int bar(int x, int y)
{
return x+y;
}
int main()
{
CHECK(bar(2,3), 2+3);
return 0;
}
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.
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)
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.
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.