Common Command-Line Options
The list of command-line options GCC accepts runs to several pages, so Table 3.2 only lists the most common ones.
Table 3.2 GCC Command-Line Options
Option |
Description |
-o FILE |
Specifies the output filename; not necessary when compiling to object code. If FILE is not specified, the default name is a.out. |
-c |
Compiles without linking. |
-DFOO=BAR |
Defines a preprocessor macro named FOO with a value of BAR on the command line. |
-IDIRNAME |
Prepends DIRNAME to the list of directories searched for include files. |
-LDIRNAME |
Prepends DIRNAME to the list of directories that are searched for library files. |
-static |
Links against static libraries. By default, GCC links against shared libraries. |
-lFOO |
Links against libFOO. |
-g |
Includes standard debugging information in the binary. |
-ggdb |
Includes lots of debugging information in the binary that only the GNU debugger, gdb, can understand. |
-O |
Optimizes the compiled code. |
-ON |
Specifies an optimization level N, 0<=N<= 3. The default level is 1 if N is not specified. |
-ansi |
Supports the ANSI/ISO C standard, turning off GNU extensions that conflict with the standard (this option does not guarantee ANSI-compliant code). |
-pedantic |
Emits all warnings required by the ANSI/ISO C standard. |
-pedantic-errors |
Emits all errors required by the ANSI/ISO C standard. |
-traditional |
Supports the Kernighan and Ritchie C language syntax (such as the old-style function definition syntax). If you don't understand what this means, don't worry about it. |
-w |
Suppresses all warning messages. In my opinion, using this switch is a very bad idea! |
-Wall |
Emits all generally useful warnings that GCC can provide. Specific warnings can also be flagged using -W{warning}. |
-werror |
Converts all warnings into errors, which will stop the compilation. |
-MM |
Outputs a make-compatible dependency list. |
-v |
Shows the commands used in each step of compilation. |
You have already seen how -c works, but -o needs a bit more discussion. -o FILE tells GCC to place output in the file FILE regardless of the output being produced. If you do not specify -o, the defaults for an input file named FILE.SUFFIX are to put an executable in a.out, object code in FILE.o, and assembler code in FILE.s. Preprocessor output goes to standard output.
Working with Libraries and Include Files
As you saw in Table 3.2, the -I{DIRNAME} option allows you to add directories to GCC's search path for include files. For example, if you store custom header files in /home/fred/include, then, in order for GCC to find them, you would use the -I option as shown in the next example:
$ gcc myapp.c I /home/fred/include o myapp
The -L option works for libraries the way that the -I option works for header files. If you use library files that reside in non-standard locations, the -L{DIRNAME} option tells GCC to add DIRNAME to the library search path and ensures that DIRNAME is searched before the standard locations.
Suppose you are testing a new programming library, libnew.so, currently stored in /home/fred/lib. (.so is the normal extension for shared librariesmore on this subject in Chapter 10, "Using Libraries.") To link against this library, your GCC command line would be something like this:
$gcc myapp.c -L/home/fred/lib lnew o myapp
The -L/home/fred/lib construct will cause GCC to look in /home/fred/lib before looking in its default library search path. The -l option tells the linker to pull in object code from the specified library. In this example, I wanted to link against libnew.so. A long-standing UNIX convention is that libraries are named lib{something}, and GCC, like most compilers, relies on this convention. If you fail to use the -l option when linking against libraries, the link step will fail and GCC will complain about undefined references to function_name.
Naturally, you can use all of these togetherin fact, doing so is quite common (and usually necessary) for all but the most trivial programs. That is, the command line
$ gcc myapp.c L/home/fred/lib I/home/fred/include lnew o myapp
instructs GCC to link against libnew.so, to look in /home/fred/lib for libnew.so, and to search in /home/fred/include for any non-standard header files.
By default, GCC links with shared libraries, so if you must link against static libraries, you have to use the -static option. This means that only static libraries will be used during the link stage. The following example creates an executable linked to the static ncurses (Chapter 23, "Getting Started with Ncurses," and Chapter 24, "Advanced Ncurses Programming," discuss user interface programming with ncurses):
$ gcc cursesapp.c -lncurses static o cursesapp
When you link against static libraries, the binary that results is much larger than the one you get if you used shared libraries. Why use a static library then? One common reason is to guarantee that users can run your programin the case of shared libraries, the code your program needs to run is linked dynamically at runtime, rather than statically at compile time. If the shared library your program requires is not installed on the user's system, she will get errors and will not be able to run your program.
The Netscape Web browser is a perfect example of this. Netscape relies heavily on Motif, an X programming toolkit. Before Motif's re-release as Open Motif (under a more open license), most Linux users could not afford to install Motif on their system. To get around this difficulty, Netscape actually installed two versions of its browser on your system; one that was linked against shared libraries, netscape-dynMotif, and one that was statically linked, netscape-statMotif. The netscape "executable" itself was actually a shell script that checked to see if you had the Motif shared library installed and launched one or the other of the binaries as necessary.
Warning and Error Message Options
GCC boasts a whole class of error-checking, warning-generating, command-line options. These include -ansi, -pedantic, -pedantic-errors, and -Wall. To begin with, -pedantic tells GCC to issue all warnings demanded by strict ANSI/ISO standard C. Any program using forbidden extensions, such as those supported by GCC, will be rejected. -pedantic-errors behaves similarly, except that it emits errors rather than warnings and stops compilation. -ansi, finally, turns off GNU extensions that do not comply with the standard. None of these options, however, guarantee that your code, when compiled without error using any or all of these options, is 100% ANSI/ISO-compliant.
Consider Listing 3.5, an example of very bad programming form. It declares main as returning void, when in fact main returns int, uses the GNU extension long long to declare a 64-bit integer, and does not call return before terminating.
Listing 3.5 Non-ANSI/ISO Source Code
/* * pedant.c - use -ansi, -pedantic or -pedantic-errors */ #include <stdio.h> void main(void) { long long int i = 0l; printf("This is a non-conforming C program\n");}
Using gcc pedant.c -o pedant, the compiler warns you about main's invalid return type:
$ gcc pedant.c o pedant pedant.c: In function 'main': pedant.c:7: warning: return type of 'main' is not 'int'
Now, add -ansi to the GCC invocation:
$ gcc -ansi pedant.c -o pedant $ gcc pedant.c o pedant pedant.c: In function 'main': pedant.c:7: warning: return type of 'main' is not 'int'
Again, GCC issued the same warning and ignored the invalid data type. The lesson here is that -ansi forces GCC to emit the diagnostic messages required by the standard. It does not ensure that your code is ANSI Ccompliant. The program compiled despite the deliberately incorrect declaration of main and the illegal data type.
Now, use -pedantic:
$ gcc -pedantic pedant.c -o pedant pedant.c: In function 'main': pedant.c:8: warning: ANSI C does not support 'long long' pedant.c:7 return type of 'main' is not 'int'
The code still compiles, despite the emitted warning. This time, however, the compiler at least noticed the invalid data type. With -pedantic-errors, however, it does not compile. GCC stops after emitting the error diagnostic:
$ gcc -pedantic-errors pedant.c -o pedant pedant.c: In function 'main': pedant.c:8: ANSI C does not support 'long long' pedant.c:7 return type of 'main' is not 'int' $ ls hello.c helper.c helper.h howdy.c pedant.c
To reiterate, the -ansi, -pedantic, and -pedantic-errors compiler options do not ensure ANSI/ISO-compliant code. They merely help you along the road. It is instructive to point out the sarcastic remark in the info file for GCC on the use of -pedantic:
"This option is not intended to be useful; it exists only to satisfy pedants who would otherwise claim that GNU CC fails to support the ANSI standard. Some users try to use '-pedantic' to check programs for strict ANSI C conformance. They soon find that it does not do quite what they want: it finds some non-ANSI practices, but not allonly those for which ANSI C requires a diagnostic."
In addition to the -ansi, -pedantic, and -pedantic-errors compiler options, gcc boasts a number of other options that issue helpful warnings. The most useful of these is the -Wall option, which causes GCC to issue a number of warnings about code that is not outright wrong, but that is potentially dangerous or that looks like it might be a mistake. The next example shows -Wall's behavior when used on pedant.c:
$ gcc Wall pedant.c o pedant pedant.c:7: warning: return type of 'main' is not 'int' pedant.c: In function 'main': pedant.c:8: warning: unused variable 'i'
Note that this time, GCC flags the variable i, which is never used. Clearly, this is not an error, but it does demonstrate a poor programming practice.
On the other end of the spectrum from -Wall is -w, which turns off all warning messages. -W{warning} has the effect of turning on a particular warning in which you are interested, indicated by warning, such as implicit function declaration (-Wimplicit-function-declaration) or functions that have an implicitly declared return type (-Wreturn-type). The former is useful because it suggests you defined a function without first declaring it or that you forgot to include the appropriate header file. The latter warning indicates that you may have declared a function without specifying its return type, in which case the return type defaults to int. Table 3.3 lists a number of useful warnings that GCC provides that are useful for catching common programming mistakes.
Tip - If you want to check your program's syntax without actually doing any compilation, call GCC with the -fsyntax-only option.
Table 3.3 GCC Warning Options
Option |
Description |
-Wcomment |
Warns if nested comments have been used (a second /* appears after a first /*) |
-Wformat |
Warns if arguments passed to printf and related functions do not match the type specified by the corresponding format string |
-Wmain |
Warns if main's return type is not int or if main is called with the incorrect number of arguments |
-Wparentheses |
Warns if parentheses have been used when an assignment is made (for example, (n=10)) in a context in which a comparison was expected (for example, (n==10)), or if parentheses would resolve an operator precedence problem |
-Wswitch |
Warns if a switch statement is missing a case for one or more of its enumerated possibilities (only applies if the index is of type enum) |
-Wunused |
Warns if a variable is declared but not used or if a function is declared static but never defined |
-Wuninitialized |
Warns if an automatic variable is used without first being initialized |
-Wundef |
Warns if an undefined identifier gets evaluated in a #if macro directive |
-Winline |
Warns if a function cannot be inlined |
-Wmissing-declarations |
Warns if a global function is defined but not declared in any header file |
-Wlong-long |
Warns if the long long type is used |
-Werror |
Converts all warnings into errors |
As you can see, GCC has the capability to catch many common and frustrating programming blunders. Listing 3.6 illustrates a number of typical coding mistakes; the sample GCC command lines that follow the listing show the -W{warning} option at work.
Listing 3.6 Common Programming Mistakes
/* * blunder.c Mistakes caught by W{warning} */ #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[ ]) { int i, j; printf("%c\n", "not a character"); /* -Wformat */ if(i = 10) /* -Wparentheses */ printf("oops\n"); if(j != 10) /* -Wuninitialized */ printf("another oops\n"); /* /* */ /* -Wcomment */ no_decl(); /* -Wmissing-declaration */ return(EXIT_SUCCESS); } void no_decl(void) { printf("no_decl\n");}
The expected warnings GCC will issue are indicated in the comments. The first attempt to compile this program uses a simple command line that does not invoke any warning options. It results in the following:
$ gcc blunder.c o blunder blunder.c:27: warning: type mismatch with previous implicit declaration blunder.c:21: warning: previous implicit declaration of no_decl' blunder.c:27: warning: 'no_decl' was previously implicitly declared to return 'int'
As you can see, in its default error-checking mode, GCC only issues warnings related to the implicit declaration of the no_decl function. It ignored the other potential errors, which include
-
The type of the argument passed to printf (a string) does not match the format specifier (a char). This will cause a -Wformat warning.
-
Both i and j are used unitialized. Either one or both of these will generate a -Wunitialized warning.
-
i is assigned a value in a context in which a comparison is intended. This should result in a -Wparentheses warning.
-
The beginning of a nested comment should generate a -Wcomment warning.
First, see if gcc catches the type mismatch in the printf statement:
$ gcc Wformat blunder.c o blunder blunder.c: In function 'main': blunder.c:11: warning: int format, pointer arg (arg 2) blunder.c: At top level: blunder.c:27: warning: type mismatch with previous implicit declaration blunder.c:21: warning: previous implicit declaration of 'no_decl' blunder.c:27: warning: 'no_decl' was previously implicitly declared to return 'int'
As you can see, the first three lines of diagnostic output show that GCC caught the type mismatch in the printf call. Next, test the -Wparentheses and -Wcomment options:
$ gcc Wparentheses Wcomment blunder.c o blunder blunder.c:19: warning: '/*' within comment blunder.c: In function 'main': blunder.c:13: warning: suggest parentheses around assignment used as truth value blunder.c: At top level: blunder.c:27: warning: type mismatch with previous implicit declaration blunder.c:21: warning: previous implicit declaration of 'no_decl' blunder.c:27: warning: 'no_decl' was previously implicitly declared to return 'int'
As anticipated, GCC emitted warnings about the apparent nested comment on line 19 and about the possibly mistaken assignment on line 13.
Finally, test -Wuninitialized:
$ gcc O Wunitialized blunder.c o blunder blunder.c: In function 'main': blunder.c:9: warning 'j' might be used uninitialized in this function blunder.c: At top level: blunder.c:27: warning: type mismatch with previous implicit declaration blunder.c:21: warning: previous implicit declaration of 'no_decl' blunder.c:27: warning: 'no_decl' was previously implicitly declared to return 'int'
Interestingly, GCC did not warn that i was being used uninitialized, although it did for j. This is because i was first flagged as a -Wparentheses warning (you can confirm this by combining -Wparentheses and -Wuninitialized). If you want to catch all of these warnings, and many more, use the -Wall option mentioned earlier. It is much shorter to type.
Note - The last example used the -O (optimization) option. This was necessary because -Wuninitialized requires its use, although this is not evident in GCC's info page.
This section demonstrated GCC's ability to catch real and potential programming errors. The next section explores another of GCC's capabilities: code optimization.