gcc: how to detect bad `bool` usage - c

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.

Related

Check if Pre processor Directive is defined in C Programming [duplicate]

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

GCC Wunused-variable warns for used variable

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.

Suppressing -Wunused-value with gcc

Considering this piece of code:
#define STC_ASSERT(X,Msg) \
(!!sizeof(struct{char STC_ASSERT;_Static_assert((X),Msg "");}))
#define A 43
#define B 42
#define C (STC_ASSERT(A-B>=0,"")?(A-B):0)
enum { c = C };
int main()
{
STC_ASSERT(1,""); //can this not generate a warning on gcc?
}
Is there anything I can do inside the STC_ASSERT _Static_assert wrapper to prevent the line in main from generating an -Wunused-value warning when compiling with gcc -Wall -Wextra?
(_Pragma with GCC diagnostic push/pop doesn't work here. For a macro like #define FOO 42, embracing it in an expression statement ( ({ 42; }) ) would do the trick but that would prevent the macro from being used in contexts where an Integer Constant Expression is required (such as the enum definition))

Why do I need to declare this function extern. It works without it

I am new to the concept of extern. Today at work I came across a large number of extern functions that were declared inside of header file; foo.h. Somewhere off in a mess of folders I found a foo.c file that contained the definition of said functions but it did not #include foo.h. When I got home I decided to play around with the extern storage class examples. After doing some reading in the "C book" this is what I came up with.
Here is what I DID NOT expect to work. But it did.
main.c
#include <stdio.h>
int data;
int main()
{
data = 6;
printf("%d\n", getData());
data = 8;
printf("%d\n", getData());
return 0;
}
externs.c
int getData()
{
extern int data;
return data;
}
bash
gcc main.c externs.c -o externs
I didn't think this would work because the function is not technically (or at least verbose) defined before main. Does this work because the default storage class for int getData() is extern? If so, why even bother with the following example (similar to what I saw at work)?
main2.c
#include <stdio.h>
#include "externs.h"
int data;
int main()
{
data = 6;
printf("%d\n", getData());
data = 8;
printf("%d\n", getData());
return 0;
}
externs.h
#ifndef _EXTERNSH_
#define _EXTERNSH_
extern int getData();
#endif
externs.c
int getData()
{
extern int data;
return data;
}
bash
gcc main2.c externs.c -o externs
Functions are implicitly extern. You can change this by declaring them as static.
You are right that it is redundant to say extern int getData(); compared to int getData(); but some people feel that it improves code clarity.
Note that since C99, your first example is ill-formed. It calls getData without that function having been declared. In C89 this performed an implicit int getData(); declaration, but since C99 that was removed. Use the compiler switches -std=c99 -pedantic to test this.
By default, GCC version 4.x or earlier compiles in a C89/C90 compatibility mode, which does not require functions to be declared before use. Undeclared functions are inferred to have a return type of int. By default, GCC 5.x or later compiles in C11 compatibility mode, which does require functions to be declared before use — as does C99.
Given that the code compiled without complaints, we can infer that you are using GCC 4.x.
Even so, you are not obliged to provide full prototypes, though you would be foolish not to. I routinely compile code with the options:
gcc -std=c11 -O3 -g -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition -Wold-style-declaration …
I suspect that there is some redundancy in there, but those options catch many problems before I get around to running the code.

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

Resources