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*/
}
}
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.
Why does this not work?:
prog.c file
#include <stdio.h>
int main(void)
{
int i, j;
printf("\n%d\n%d\n", i, j);
return 0;
}
debug file:
#!/bin/bash
g++ -Wall -Wextra -Wpedantic -O0 -g3 -fsanitize=address -o temp/debug.out src/prog.c
./temp/debug.out
running:
./debug
prog.c: In function ‘main’:
prog.c:6:9: warning: ‘i’ is used uninitialized in this function [-Wuninitialized]
printf("\n%d\n%d\n", i, j);
^~~~~~~~~~~~~~~~~~~~~~~~~~
prog.c:6:9: warning: ‘j’ is used uninitialized in this function [-Wuninitialized]
0
0
==90==LeakSanitizer has encountered a fatal error
==90==HINT: For debugging, try setting environment variable LSAN_OPTION=verbosity=1:log_threads=1
==90==LeakSanitizer does not work under ptrace (strace, gdb, etc)
I'm new to using debuging tools but there isn't much to read on this topic except man pages of compilers. So please can someone help me?
This was executed on Windows 10 subsystem for linux (Ubuntu) on freshly openned terminal.
I'd like to use -fno-sanitize=all option I found in man pages of gcc but it doesn't seem to say a word on any mistake I came up with.
I found out it was problem of WSL i used (I didn't think it was important to say i use one)
Turns out i need to write LSAN_OPTION=verbosity=1:log_threads=1; g++ -Wall...
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.
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 recently had to type in a small C test program and, in the process, I made a spelling mistake in the main function by accidentally using vooid instead of void.
And yet it still worked.
Reducing it down to its smallest complete version, I ended up with:
int main (vooid) {
return 42;
}
This does indeed compile (gcc -Wall -o myprog myprog.c) and, when run, it returns 42.
How exactly is this valid code?
Here's a transcript cut and pasted from my bash shell to show what I'm doing:
pax$ cat qq.c
int main (vooid) {
return 42;
}
pax$ rm qq ; gcc -Wall -o qq qq.c ; ./qq
pax$ echo $?
42
It's simply using the "old-style" function-declaration syntax; you're implicitly declaring an int parameter called vooid.
It's valid code, because myprog.c contains:
int main (vooid) // vooid is of type int, allowed, and an alias for argc
{
return 42; // The answer to the Ultimate Question
}
vooid contains one plus the number of arguments passed (i.e., argc). So, in effect all you've done is to rename argc to vooid.
In C, the default type for a function argument is int. So, your program is treating the word vooid as int main(int vooid), which is perfectly valid code.
It is only gcc -std=c89 -Wall -o qq qq.c and gcc -std=gnu89 -Wall -o qq qq.c don't emit a warning. All the other standards emit a warning about implicit type int for vooid.
int main(chart) behaves the same way as does int main (vooid).
return vooid; returns the number of command line arguments.
I tested with gcc 4.4.5 on Debian testing system.