http://www.openlogic.com/wazi/bid/332308/become-a-gcc-expert-with-these-little-known-command-line-options
The GNU Compiler Collection (GCC) is easy to use, but it offers so many command-line options that no one can remember them all. Here are five uncommon command-line options you can use to get the most out of GCC.
To illustrate these examples, I used GCC 4.7.3 running on Ubuntu Linux 13.04 with Bash 4.2.45.
For instance, suppose you compile the program helloworld.c using the
If you compile the same code with the
Read the gcc man page for other warnings
To see how it works, suppose the source file helloworld.c contains following code:
If instead you compile the code with the
The GNU Compiler Collection (GCC) is easy to use, but it offers so many command-line options that no one can remember them all. Here are five uncommon command-line options you can use to get the most out of GCC.
To illustrate these examples, I used GCC 4.7.3 running on Ubuntu Linux 13.04 with Bash 4.2.45.
-save-temps
In simplest terms, the GCC compilation process internally follows four stages:- In the first stage, the preprocessor expands all the macros and header files, and strips off comments.
- In the second stage, the compiler acts on the preprocessed code to produce assembly instructions.
- In the third stage, the assembler converts the assembly instructions into machine-level code (object files).
- In the final stage, the linker resolves all the unresolved symbols and combines all the object files to produce an executable.
-save-temps
option.For instance, suppose you compile the program helloworld.c using the
-save-temps
option:$ gcc -Wall -save-temps helloworld.c -o helloworldAlong with the final executable, gcc produces three other files. helloworld.i is the output of the preprocessing stage, helloworld.s is the output of the compilation stage, and helloworld.o is the output of the assembly stage.
-Wextra
Many developers use the option-Wall
to enable warnings during the compilation process, but -Wall
does not report all possible warnings. It leaves out, for example, warnings about:- Missing parameter type
- Comparison of a pointer with integer zero using >, <, >=, or <=.
- Ambiguous virtual bases
#includeAs you can see, the type of the argument "a" is not specified in function func(). This could be a typo on the part of the programmer who, for example, meant to declare "a" as a "long long" integer, but without that declaration the compiler will assume the default type of variable "a" as int. If you compile this code with thevoid func(a) { printf("\n func() is passed parameter [%d]\n",a); return; } int main(void) { printf("\n HELLO \n"); func(0xFFFFF); return 0; }
-Wall
option,
gcc does not produce any warning, and the program could produce
undesired results. For example, if a "long long" value that is larger
than the maximum value that an "int" can hold is passed as an argument
to func(), the program will behave incorrectly.If you compile the same code with the
-Wextra
option enabled, you should see the following output:$ gcc -Wall -Wextra helloworld.c -o helloworld helloworld.c: In function 'func': helloworld.c:4:6: warning: type of 'a' defaults to 'int' [-Wmissing-parameter-type]Once you know about this problem, you can easily fix it by explicitly mentioning the type of function argument "a."
-Wextra
offers similar warnings for pointer comparison problems. Consider the following code:#includeThe pointer "ptr" is being compared with the integer zero in the function func(). This statement is useless, as ptr clearly contains the address of the variable "a," which will always be a positive value. The programmer must have missed the dereference operator * before ptr while comparing its value with zero. Just as in the previous example, if you compile this code with thevoid func() { int a = -1; int *ptr = &a; if(ptr >= 0) { a = a+1; } printf("\n a = [%d]\n",a); return; } int main(void) { printf("\n HELLO \n"); func(); return 0; }
-Wall
option, gcc does not
produce any warning, but the program will produce wrong result (a=0) in
the output. On the other hand, when you use -Wextra
, gcc reports:$ gcc -Wall -Wextra helloworld.c -o helloworld helloworld.c: In function 'func': helloworld.c:9:12: warning: ordered comparison of pointer with integer zero [-Wextra]As soon as you see a warning related to pointer comparison with zero, you immediately know you have a typo in your code, which you can easily fix by replacing
(ptr>=0)
with ((*ptr)>=0)
in this case.Read the gcc man page for other warnings
-Wextra
produces.-Wfloat-equal
New programmers sometimes try to compare floating point variables using the == operator – something you should never do because of the way floating point numbers are represented internally. The gcc compiler's-Wfloat-equal
option produces a warning whenever it encounters a floating point comparison. Consider:#includeHere, the float arguments to the function func() are being compared using the == operator. When you compile this code without using thevoid func(float a, float b) { printf("\n Inside func() \n"); if(a == b) { printf("\n a == b\n"); } return; } int main(void) { printf("\n HELLO \n"); func(1.345, 1.345678); return 0; }
-Wfloat-equal
option, you'll see no warning, but with it, you should see output like this:$ gcc -Wfloat-equal helloworld.c -o helloworld helloworld.c: In function 'func': helloworld.c:7:10: warning: comparing floating point with == or != is unsafe [-Wfloat-equal]If you see that your code is directly comparing floats, you should drop the direct comparison and think of better logic to solve the problem.
-g
If you use the GNU debugger (GDB) to debug, or Valgrind to detect memory leaks in your program, always compile the program with the-g
option, which produces debugging information in the operating system's
native format. Other tools can use this information to produce detailed
output.To see how it works, suppose the source file helloworld.c contains following code:
#includeIf you compile the code without the#include #include void func() { char *p = (char*) malloc(10); printf("\n Inside func() \n"); return; } int main(void) { printf("\n HELLO \n"); func(); return 0; }
-g
option and run Valgrind's memcheck tool, you'll see a problem – a memory leak:$ valgrind --tool=memcheck --leak-check=yes ./helloworld ==3471== Memcheck, a memory error detector ==3471== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al. ==3471== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info ==3471== Command: ./helloworld ==3471== HELLO Inside func() ==3471== ==3471== HEAP SUMMARY: ==3471== in use at exit: 10 bytes in 1 blocks ==3471== total heap usage: 1 allocs, 0 frees, 10 bytes allocated ==3471== ==3471== 10 bytes in 1 blocks are definitely lost in loss record 1 of 1 ==3471== at 0x4C2CD7B: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==3471== by 0x40058D: func (in /home/himanshu/practice/helloworld_dir/helloworld) ==3471== by 0x4005B6: main (in /home/himanshu/practice/helloworld_dir/helloworld) ==3471== ==3471== LEAK SUMMARY: ==3471== definitely lost: 10 bytes in 1 blocks ==3471== indirectly lost: 0 bytes in 0 blocks ==3471== possibly lost: 0 bytes in 0 blocks ==3471== still reachable: 0 bytes in 0 blocks ==3471== suppressed: 0 bytes in 0 blocks ==3471== ==3471== For counts of detected and suppressed errors, rerun with: -v ==3471== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 2 from 2)The memcheck tool is able to detect the memory leak, but it is unable to say where the leak actually takes place. Without that information, you could have a big problem tracking down the leak when you're working on projects that contain large source files.
If instead you compile the code with the
-g
option before you run memcheck, the tool can pinpoint the problem:$ valgrind --tool=memcheck --leak-check=yes ./helloworld ==3517== Memcheck, a memory error detector ==3517== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al. ==3517== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info ==3517== Command: ./helloworld ==3517== HELLO Inside func() ==3517== ==3517== HEAP SUMMARY: ==3517== in use at exit: 10 bytes in 1 blocks ==3517== total heap usage: 1 allocs, 0 frees, 10 bytes allocated ==3517== ==3517== 10 bytes in 1 blocks are definitely lost in loss record 1 of 1 ==3517== at 0x4C2CD7B: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==3517== by 0x40058D: func (helloworld.c:7) ==3517== by 0x4005B6: main (helloworld.c:16) ==3517== ==3517== LEAK SUMMARY: ==3517== definitely lost: 10 bytes in 1 blocks ==3517== indirectly lost: 0 bytes in 0 blocks ==3517== possibly lost: 0 bytes in 0 blocks ==3517== still reachable: 0 bytes in 0 blocks ==3517== suppressed: 0 bytes in 0 blocks ==3517== ==3517== For counts of detected and suppressed errors, rerun with: -v ==3517== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 2 from 2)You might also want to profile your program. Code profiling can tell you things such as how much time each function consumes, how many times a function gets called, and which parts of your program are slow and need improvement. In Linux, a popular code profiling tools is the GNU profiler, or gprof. This tool requires the code to be compiled (and linked) using gcc's
-pg
option. GNU gprof produces detailed profiling information in form of flat profile and call graph.@file
All of these options may be useful, and you may want to use some or all of them together for all of your compiles. If you find yourself using many command-line options while compiling your programs, you can put all the options in a file and pass the file name to gcc to use all the flags in the file together. For instance, you could create a file named options that contains the line-Wall -Wextra -Wfloat-equal
, then pass the file name as a command-line option to gcc:$ gcc @options helloworld.c -o helloworldKeeping your gcc compiler options in an options file makes managing multiple command-line options easy.
No comments:
Post a Comment