I have a large codebase of C code which part of it is generated code from the Oracle Pro*C precompiler.
We use the GNU gcc compiler.
The Pro*C precompiler generates code that contains unused variables that emits many warnings related to -Wunused-variable which I'd like to ignore.
I've tried the following which I found in other questions but it doesn't see to work for C code (cut down to a minimal example).
int main(void)
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
int a=0;
#pragma GCC diagnostic pop
int b=0;
return 0;
}
I still get the -Wunused-variable error for variable a.
aa.c: In function 'main':
aa.c:8:13: warning: unused variable 'b' [-Wunused-variable]
int b=0;
^
aa.c:6:14: warning: unused variable 'a' [-Wunused-variable]
int a=0;
^
GCC command:
gcc-8 -Wall -Wextra -pedantic aa.c -o a
Incase you are wondering, if I remove the pop pragma, no warnings are issued.
The solution I found was to add __attribute__((unused)) before the generated variables that were problematic. In this situation there are always only 4 relevant variables so it was possible.
I wrote a bash command in the make file right after the Pro*C precompiler:
for var in varA varB varC varD; do sed -i "0,/${var}/{s/\(${var}\)/__attribute__((unused))\1/}" $file_name; done
Hope it can be helpful for someone.
Related
I want to show that arrays can't be defined with a variable for the length in C89 or C90.
I use GCC on Windows from TDM GCC:
C:\TDM-GCC-64\bin> .\gcc.exe --version
gcc.exe (tdm64-1) 10.3.0
My compilation options are:
gcc.exe -Wall -g -ansi -save-temps -c
I tried:
int main()
{
int i;
int tab[i];
tab[0] = 10;
return 0;
}
But it compiles fine:
gcc.exe -Wall -g -ansi -save-temps -c main.c -o main.o
gcc.exe -o Sandbox.exe main.o
main.c:6:9: warning: variable 'tab' set but not used [-Wunused-but-set-variable]
6 | int tab[i];
| ^~~
main.c:6:5: warning: 'i' is used uninitialized in this function [-Wuninitialized]
6 | int tab[i];
| ^~~
Output file is bin\Debug\Sandbox.exe with size 196.89 KB
Then:
int test(int i)
{
int tab[i];
tab[0] = 10;
return 0;
}
Compiles too:
main.c: In function 'test':
main.c:5:9: warning: variable 'tab' set but not used [-Wunused-but-set-variable]
5 | int tab[i];
| ^~~
Output file is bin\Debug\Sandbox.exe with size 196.90 KB
Or:
int main()
{
volatile int i;
int tab[i];
tab[0] = 10;
return 0;
}
Only this is not compiling:
int main()
{
// Comment
return 0;
}
error: C++ style comments are not allowed in ISO C90
What am I missing?
Thanks!
Variable length array is a GCC extension in older standard versions. Extensions are "compatible" with the standard. If you want to exactly adhere to the standard, i.e. you want to get a message when using an extension, add -pedantic option (and -pedantic-errors for errors).
Gcc docs: https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Variable-Length.html#Variable-Length , https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Warning-Options.html#Warning-Options .
gcc has sloppy standard compliance per default. It defaults to lax C conformance + GNU extensions, equivalent to -std=gnu89 (current version defaults to -std=gnu17).
When you type -ansi it does not mean conforming mode, but rather just the very same thing as -std=c89, "lax C89 mode". This compiler option may disable some GNU extensions... maybe... while keeping others. The difference between -std=c89 and -std=gnu89 is as poorly documented as the rest of gcc. We can read the unfriendly manual and it says:
For example, -std=c90 turns off certain features of GCC that are incompatible with ISO C90, such as the asm and typeof keywords, but not other GNU extensions that do not have a meaning in ISO C90
gcc supported variable-length arrays as an extensions even before C99, so switching out the GNU option ought to disable them, but not so... As far as I know, there is no official documentation over what features -std=c89 shuts off or at least I can't find it.
What's important to realize is that -std=c89/-ansi alone does not push gcc into conforming mode! To do that, you need to do -std=c89 -pedantic or if you will -std=c89 -pedantic-errors. After which you'll get a diagnostic like this:
error: ISO C90 forbids variable length array 'tab'
And when compiling with these two options in combination, gcc probably has the best standard compliance of any compiler out there.
Here is the content of source file get.c :
#include <stdio.h>
int main(){
//int i = 0;
char b[10];
gets(b);
puts(b);
return 0;
}
When I compile it with these command
gcc -o get get.c -Wall -Werror
The output is
/tmp/ccYEWZvx.o: In function `main':
get.c:(.text+0x10): warning: the `gets' function is dangerous and should not be used.
But when change the code to
#include <stdio.h>
int main(){
int i = 0; // **this line just be uncommented**
char b[10];
gets(b);
puts(b);
return 0;
}
Using the same command, the output is
cc1: warnings being treated as errors
get.c: In function 'main':
get.c:4: error: unused variable 'i'
So, why this unused variable warning be treated as error, while the use of gets() not?
The gets() warning is being issued by the linker not the compiler, so the compiler settings do not apply.
Only the linker is able to determine that the symbol is resolved with the standard library gets() rather than some other implementation with the same name.
To instruct the linker to treat warnings as errors you need to pass it the --fatal-warnings option. In turn when not invoking the linker directly, options are passed to the linker by gcc using the -Wl option in a comma separated list:
gcc -o get get.c -Wall -Werror -Wl,--fatal-warnings
Note that the GNU linker is documented separately from the compiler, as part of binutils. The linker options are described here.
If you look at the output from the first example, it says the "error" is in an object file, which means it is generated by the linker.
The second error is generated by the compiler, which means there is no object file being generated and so the linker will not be invoked.
-Werror make all warnings as errors, to print only security warnings you can use: -Wformat -Wformat-security
You can read warnings options here https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
The compiler abort the compilation if an error is occurred, instead it continue the compilation if there are one or more warnings.
I created a basic C project in Xcode and modified the starter code in main.c slightly. I also went into the build settings and told it to use ANSI-C. Here's the code I have:
int main(int argc, const char * argv[])
{
// a statement!
printf("Hello, World!\n");
// shouldn't this cause a compiler error?
// the variable isn't declared at the top of the scope.
int x;
x += 10;
return 0;
}
Obviously, it doesn't do much, but I expected the variable declaration to produce a compiler error (since older versions of C require variable declarations at the beginning of the scope, before other statements). However, Xcode happily compiles it and runs it with neither an error or warning.
I might be making a dumb mistake somewhere, but I'm trying to understand why this code compiles. I've read that C99 and C11 allow you to declare variables anywhere, so this would work, but I explicitly set the project to use ANSI-C. Is this just the way Apple's LLVM compiler works? Or am I missing something elsewhere?
TL;DR You need to add -pedantic (or -Wdeclaration-after-statement) to -ansi to get the warning you want.
Somewhat to my surprise, both clang (from Apple XCode 7.2) and gcc (from GCC 5.3.0, which I built), accept the code when compiled with either -std=c90 or -ansi even though it is not strictly compliant with C90.
However, both complain when told to be -pedantic.
$ clang -ansi -c xyz.c
$ clang -std=c90 -c xyz.c
$ gcc -std=c90 -c xyz.c
$ which gcc
/opt/gcc/v5.3.0/bin/gcc
$ gcc -std=c90 -pedantic -c xyz.c
xyz.c: In function ‘main’:
xyz.c:7:5: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
int x;
^
$ clang -pedantic -std=c90 -c xyz.c
xyz.c:7:9: warning: ISO C90 forbids mixing declarations and code [-Wdeclaration-after-statement]
int x;
^
1 warning generated.
$ clang -pedantic -ansi -c xyz.c
xyz.c:7:9: warning: ISO C90 forbids mixing declarations and code [-Wdeclaration-after-statement]
int x;
^
1 warning generated.
$
The file xyz.c is your source code with the comments stripped, #include <stdio.h> added at the top, and int main(void) in place of int main(int argc, char **argv) since the code doesn't use the arguments.
Note that your code has undefined behaviour; incrementing an uninitialized variable is a bad idea.
I was reading C programming from a book that says all variables have to be declared in the beginning of the function. I tried following code but didn't issue any error. I am using mingw and codeblocks. The code is as follows:
#include <stdio.h>
int main()
{
int i=10;
printf("%d\n",i);
int j=20;
printf("%d\n",j);
return 0;
}
Do I have to change any compiler setting or something to make it compatible with the standard given in the book?
I am using -std=c89 compiler option. See the compilation messages below:
-------------- Clean: Debug in HelloWorld (compiler: GNU GCC Compiler)---------------
Cleaned "HelloWorld - Debug"
-------------- Build: Debug in HelloWorld (compiler: GNU GCC Compiler)---------------
mingw32-gcc.exe -Wall -std=c89 -g -c D:\MyCodeBlocksProjects\HelloWorld\main.c -o obj\Debug\main.o
mingw32-g++.exe -o bin\Debug\HelloWorld.exe obj\Debug\main.o
Output size is 68.53 KB
Process terminated with status 0 (0 minutes, 0 seconds)
0 errors, 0 warnings (0 minutes, 0 seconds)
all variables have to be declared in the beginning of the function.
To be precise, they have to be declared in the beginning of a block. And this is only true in C89. C99 has removed this limit. So you can change your compiler to strict C89 mode. For example, for GCC, it's -std=c89 option. To obtain all the diagnostics required by the standard, you should also specify the option -pedantic.
To demonstrate what I mean by in the beginning of a block, this is legal C89 syntax:
void foo()
{
int x = 1;
x = x + 1;
{
int y = 42; /**OK: declaration in the beginning of a block*/
}
}
In C, function declarations can be prototype or non-prototype declarations. For example, consider the following minimal program:
int foo (); /* non-prototype declaration */
int bar (void); /* prototype declaration */
int main (int argc, char **argv)
{
return 0;
}
Although in C99 non-prototype declarations are obsolete, I cannot get GCC to complain about them. For example, compiling the above program with GCC and all errors enabled just succeeds:
$ gcc -std=c99 -pedantic -Werror -Wall test.c
$
Is there any way to persuade GCC to emit warnings for function declarations that aren't prototypes?
(Question inspired by an answer by Keith Thompson.)
I think the option you are looking for is -Wstrict-prototypes
Note that gcc with -std=c99 -pedantic -Wall options doesn't issue any warning for the old style function declarations but C doesn't require the implementation to issue a diagnostic in presence of the old style function declarations.
C characterizes the use of old style function declaration as obsolescent since C89 but it it still valid C code (in C89/C99/C11).