GCC Wunused-variable warns for used variable - c

I am using GCC version 8.2
On several pieces of code, I use small functions. On each one of the functions, I have tests (i.e. Unity framework tests). The tests are defined as #define macros, testing very specific things. For instance, if a number if positive.
Now, when compiling the code using -Wextra flag, I am getting warning about unused variables, although I am using them on the defined macros.
The question is, GCC does not recognize a macro as using a variable, or am I missing something?
Example:
#define compare(a,b) ( ((a) == (b)) ? 1 : 0 )
...
void f() {
int a;
a = f1();
if(compare(a,123))
printf("It works");
}
In this case, GCC would warning about unused variable a, although it is being used by the macro (besides being attributed a value by function f1()).

This is not the case, at least with the example you supplied. Here is a Minimal, Complete, and Verifiable demonstration:
#include <stdio.h>
#define compare(a,b) ( ((a) == (b)) ? 1 : 0 )
int f1() {
return 42;
}
void f() { // your code
int a;
a = f1();
if (compare(a, 123))
printf("It works");
}
int main(int argc, char *argv[]) {
f();
return 0;
}
When compiled with gcc -Wall -Wunused (yes, this is redundant) using gcc 8.2 or 7.3 there are no warnings or errors.

Related

gcc: how to detect bad `bool` usage

Is there some way to detect the bad usage of bool values in code like
#include <stdbool.h>
void *foo(void)
{
return false;
}
int bar(void)
{
return true;
}
Both functions are accepted by gcc (8.3.1) and clang (7.0.1) without any warnings
$ gcc -Wall -W -pedantic -c x.c
$ clang -Xclang -analyzer-checker=alpha --analyze -Wall -W -pedantic -c x.c
$ clang -Wall -W -pedantic -c x.c
$
Compiling as C++ code would detect the problem in foo() but is not an option but rest of code is C, not C++.
Are there other (-W) options or switches which would create diagnostics for these cases?
C defines the <stdbool.h> macros true and false as expanding to integer constant expressions of value 1 and 0 respectively. Since they're ints and bool (_Bool) in itself is an integer type, any such usage is equally valid. Even the value of the boolean expressions in C is an int and not a bool, so there is not much help for you with the bar function.
However, foo is a different beast - if the return value were true then it would be caught right away because 1 is not convertible to a pointer. false, having the integer constant value 0 is a null-pointer constant and will be converted to null pointer. You could perhaps catch the incorrect use by replacing the #include <stdbool.h> with something that does the inclusion but defines false as say 0.0 which is a falsy value but not an integer constant expression.
Make the example less trivial:
bool x;
void *foo(void)
{
return x;
}
int bar(void)
{
return x;
}
and it want compile at all.
usually true and false are just definitions and have value 1 and 0
From the stdbool.h header file
#ifndef _STDBOOL_H
#define _STDBOOL_H
#ifndef __cplusplus
#define bool _Bool
#define true 1
#define false 0
#else /* __cplusplus */
in your first example you just return zero and most compilers will not warn as they treat it as NULL. Try to return true and you will get the warning.

dead code remover adbout gcc -O and higher

I have written a simple code like this
#include <stdlib.h>
#include <stdio.h>
//#define CONFIG_TARGET_X86_64
#ifdef CONFIG_TARGET_X86_64
static void A( )
{
printf("A\n");
}
#else
void A( );
#endif
static void B( )
{
printf("B\n");
}
static int xx( )
{
#ifdef CONFIG_TARGET_X86_64
return 1;
#else
return 0;
#endif
}
int main(void)
{
if (xx( )) /* define CONFIG_TARGET_X86_64 */
A( );
else
B( );
}
If we don't define the CONFIG_TARGET_X86_64, xx( ) will always return FALSE, so functiopn A which is only declared, but not implemented will never be called(dead code).
compile it with gcc -O0
/tmp/cctSpgGk.o: In function `main':
1.c:(.text+0x34): undefined reference to `A'
collect2: error: ld returned 1 exit status
But it can be compiled by -O1 or higher.
use GCC V6.1.0
It seems that one of the optimization options in the -O1 option eliminates the dead code, I have seen the optimize doccument about GCC
https://gcc.gnu.org/onlinedocs/gcc-6.4.0/gcc/Optimize-Options.html
but I can't find it.
So I just want to compile this code under the -O0 option, Is it possible ? Are there some optimization flags help me to do this?
Thanks
What's worth noting here is this declares a method signature:
void A( );
Where this declares a method implementation:
void A( ) { };
There is a huge difference between these two.
If you're referencing a function with a call you need to implement it. The compiler will decide if it'll optimize that function call away or not depending on other factors, but it'll need to know what that function does, not just how it's called.
You can declare A as weak:
void A (void) __attribute__ ((weak));
Then the linker will ignore the undefined symbol reference, but a call to this function will lead to a crash.

C: macro produced warning "statement with no effect"

I have following code in C:
int do_something(void);
#ifdef SOMETHING
#define DO_SOMETHING() do_something()
#else
#define DO_SOMETHING() 0
#endif
This code produced warning "statement with no effect" when compiled without SOMETHING defined. I am trying to fix it, but there is one problem - code which uses this macro sometimes checks that "return value" and sometimes ignores it. Because of this I cannot use the easiest solution - casting to void in macro itself.
Is it possible to write macro which allows to compare "returned value" and does not produce this warning when it is ignored?
I use gcc to compile my code.
Three possible solutions:
Define a do_nothing function, which will get optimized out by gcc:
int do_something(void);
int do_nothing(void) { return 0; }
#ifdef SOMETHING
#define DO_SOMETHING() do_something()
#else
#define DO_SOMETHING() do_nothing()
#endif
Or, modify the do_something implementation to move the #ifdef check there
int do_something(void)
{
#ifndef SOMETHING
return 0;
#endif
// Your implementation here
}
You can also ignore the warning using #pragma directives.
By the way, which version of gcc and with which flags are you compiling? gcc -Wall -pedantic with GCC 4.9 doesn't produce the warning.
#include <stdio.h>
int do_something(void);
#ifdef SOMETHING
#define DO_SOMETHING() do_something()
#define DO_SOMETHING_ASSIGN() do_something()
#else
#define DO_SOMETHING()
#define DO_SOMETHING_ASSIGN() 0
#endif
int do_something(void)
{
static int cnt=0;
/* code for do something here */
++cnt;
printf("do_something has been called %d %s!\n",cnt,
(cnt==1)?"time":"times");
return cnt;
}
void main(void)
{
int x;
DO_SOMETHING();
x=DO_SOMETHING_ASSIGN();
printf("%d %d\n",x,DO_SOMETHING_ASSIGN());
puts("end!!!");
}
I hope this is usefull to you!
If you save this code as main.c, you may compile it with:
gcc main.c -o main
when you run main, you obtain the following output:
0 0
end!!!
If you compile it with:
gcc main.c -DSOMETHING -o main
When you run main, you obtain the following output:
do_something has been called 1 time!
do_something has been called 2 times!
do_something has been called 3 times!
2 3
end!!!

identify volatile declaration in debug information / disassembly

I'm looking for a creative solution for making sure that variables delivered to a specific macro are declared with type volatile in C language, with TMS470 compiler. meaning:
good method:
volatile int *_p_reg;
VOLATILE_MACRO(_p_reg);
compilation failure:
int *_p_reg;
VOLATILE_MACRO(_p_reg);
I wish to perform the verification after the compilation, meaning going over the disassembly or the debug information and identify those calls.
I can't seem to find any evidence for the volatile in the debug info.
any ideas?
thanks!
I wouldn't expect there to be any, but of course it's totally up to the compiler.
You could of course re-architect it so that the macro does the whole definition, i.e.
#define VOLATILE_MACRO(t, p) volatile t p
and use it like:
VOLATILE_MACRO(int, _p_reg);
but of course that might not work for you.
Two possible solutions using gcc extensions. The run-time version uses __builtin_types_compatible_p and an assert. The compile-time version is similar but uses a hack to get a static assert which fires at compile-time (albeit with a rather cryptic error message):
Run-time
#include <stdio.h>
#include <assert.h>
#define VOLATILE_MACRO(p) \
assert (__builtin_types_compatible_p(typeof(p), typeof(volatile int *)))
int main()
{
volatile int * x;
int * y;
VOLATILE_MACRO(x); // <<< OK
VOLATILE_MACRO(y); // <<< run-time error
return 0;
}
Compile-time
#include <stdio.h>
#include <assert.h>
#define A BUILD_NAME(__LINE__)
#define BUILD_NAME(line) BUILD_NAME2(line)
#define BUILD_NAME2(line) assert_ ## line
#define STATIC_ASSERT(test) typedef char A[(test) ? 1 : -1]
#define VOLATILE_MACRO(p) \
STATIC_ASSERT (__builtin_types_compatible_p(typeof(p), typeof(volatile int *)))
int main()
{
volatile int * x;
int * y;
VOLATILE_MACRO(x); // <<< OK
VOLATILE_MACRO(y); // <<< compile error
return 0;
}
Note that if you need to support other volatile types then the macro can simply be extended with multiple chained __builtin_types_compatible_p tests, e.g.
#define VOLATILE_MACRO(p) \
assert (__builtin_types_compatible_p(typeof(p), typeof(volatile int *)) ||
__builtin_types_compatible_p(typeof(p), typeof(volatile short *)))

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

Resources