When developing applications for Linux, most of the cases are used in C language, so almost every Linux programmer faces how to flexibly use the C compiler. The most commonly used C language compiler under Linux is a GNU Compiler Collection. It is a compilation system in accordance with the ANSI C standard in the GNU project, which can compile the program written in languages such as C, C and Object C. GCC is not only very powerful, but also is very flexible. The most worthy of the right thing is that it can support various languages through different front-end modules, such as Java, Fortran, Pascal, Modula-3, and ADA, etc.
Open, freedom and flexible are the charm of Linux, and this is reflected in the GCC is that the programmer can better control the entire compilation process by it. When using the GCC compiler, the compilation process can be subdivided into four stages:
◆ Pre-processing
◆ Compilan
◆ Assembling
◆ Link (Linking)
Linux programmers can end according to their needs, let GCC end in any phase of compilation, in order to check or use the compiler to control the output information of this phase, or control the last generated binaries to control the debug code of different quantities and types Come ready for future debugging. Like other commonly used compilers, GCC also provides flexible and powerful code optimization functions, using it to generate higher code of execution efficiency.
GCC provides more than 30 warning information and three warning levels that use them help to enhance the stability and portability of the program. In addition, GCC also has a lot of extension of standard C and C languages, improves the performance efficiency of the program, which helps the compiler to optimize the code optimization, and can reduce the workload of the programming.
GCC starts
Before learning to use GCC, the following example can help users quickly understand the GCC's working principle and use them to actually use the actual project development. First enter the code shown in Listing 1 with a familiar editor:
Listing 1: Hello.c
#include
Int main (void)
{
Printf ("Hello World, Linux Programming! / N");
Return 0;
}
Then perform the following command to compile and run this program:
# GCC Hello.c -o Hello
# ./hello
Hello World, Linux Programming!
From a programmer's point of view, just simply execute a GCC command, but from the perspective of the compiler, it is necessary to complete a series of very complicated work. First, the GCC needs to call the preprocessor CPP, which is responsible for expanding the macro defined in the source file and inserts the "#include" statement in the "#include" statement; then, the GCC will call the CCL and AS will process the source code. Compile to target code; Finally, the GCC calls the linker LD to link the generated target code into an executable program.
In order to better understand the working process of GCC, the above-described compilation process can be divided into several steps separately, and the results of each step are observed. The first step is to perform precompilation, using the -e parameter allows GCC to stop compiling the compilation process after the pre-processing:
# gcc -e hello.c -o hello.i
If you look at the content in the Hello.cpp file, you will find that stdio.h is indeed inserted into the file, and other macro definitions that should be pre-processed have been processed. The next step is to compile hello.i as a target code, which can be done by using the -c parameter: # gcc -c hello.i -o hello.o
The GCC defaults to the .I file as a pre-processed C language source code, so the above command will automatically skip the pre-processes step and start the compilation process, or use the -X parameter to get the GCC from the specified steps to start compiling. The final step is to link the generated target file into an executable:
# GCC Hello.o -o Hello
When using modular design ideas for software development, the entire program is usually constructed from multiple source files, and a plurality of compilers are formed, and these compilers can be managed well with GCC. Suppose there is a program consisting of two source files of foo1.c and foo2.c, in order to compile them, and finally generate executable program foo, you can use the following command:
# GCC foo1.c foo2.c -o foo
If there is more than one process, GCC will still be done in accordance with the process of pre-processing, compile and link. If it is deep, the above order is roughly equivalent to the following three commands:
# gcc -c foo1.c -o foo1.o
# gcc -c foo2.c -o foo2.o
# gcc foo1.o foo2.o -o foo
When compiling a project containing many source files, if only one GCC command is used to complete the compilation, it is very wasteful. Assuming that there are 100 source files in the project need to be compiled, and each source file contains a 100,000 line code. If only one GCC command is used as above, the GCC needs to be re-compiled each source file. Then connect all again. Obviously, this is quite a lot of time, especially when the user only modifies one of the files, it is not necessary to recoilate each file over, because many of the target files that have been generated will not change. To solve this problem, the key is to flexibly use GCC, while also use tools like Make.
Warning prompt function
GCC contains a complete error check and warning prompt, which can help Linux programmers write more professional and beautiful code. First read the procedure shown in Listing 2, this code is very bad, carefully check it is not difficult to pick out a lot of problems:
◆ The return value of the main function is declared as Void, but it should actually be int;
◆ Use the GNU syntax extension, even if you use long long to declare 64-bit integers, do not comply with ANSI / ISO C language standards;
◆ The main function does not call the Return statement before termination.
Listing 2: Illcode.c
#include
Void main (void)
{
Long long int var = 1;
Printf ("IT IS Not Standard C C Code! / N");
}
Let's take a look at how GCC helps programmers to discover these errors. When the GCC is compiling the source code that does not conform to the ANSI / ISO C language standard, if the -pedantic option is added, the corresponding warning message will be generated using the extension syntax:
# gcc -pedantic illcode.c-ilcode
Illcode.c: in function `main ':
Illcode.c: 9: ISO C89 Does Not Support `long long '
Illcode.c: 8: Return Type of `main 'is not` int' Need not to note that the -pedant Compilation option does not guarantee that the compiler is fully compatible with the ANSI / ISO C standard, it can only be used to help Linux The programmer is getting closer and closer to this goal. Alternatively, the -pedantic option helps programmers find some code that does not meet the ANSI / ISO C standard, but not all, in fact, only those cases that require compiler diagnosis in the ANSI / ISO C language standards, it is likely to Founded by GCC and warned.
In addition to -pedantic, GCC also has some other compilation options that can also produce useful warning messages. Most of these options begin with -w, where the most valuable matters -wall, use it to make GCC to produce as much warning message:
# gcc -wall illmode.c-ilcode
Illcode.c: 8: Warning: Return Type of `main 'is not` int'
Illcode.c: in function `main ':
Illcode.c: 9: Warning: unused variable `var '
Although the warning information given by GCC is strictly in a strict sense, it is likely that it is a mistake of the wrong hat. A excellent Linux programmer should try to avoid warning information, so that your code is always simple, beautiful and robust.
In terms of processing warning, another commonly used compilation option is -werror, which requires GCC to process all warnings as an error, which is very useful when using the automatic compilation tool (such as Make, etc.). If you compile the -werror option, the GCC will stop compiling all wherever the warning is generated, forcing the programmer to modify its own code. Only when the corresponding warning information is eliminated, the compilation process may continue to advance forward. The implementation is as follows:
# gcc -wall -wrror isolacode.c -o illde
CC1: Warnings Being Treated As ErrorS
Illcode.c: 8: Warning: Return Type of `main 'is not` int'
Illcode.c: in function `main ':
Illcode.c: 9: Warning: unused variable `var '
For Linux programmers, the warning information given by GCC is valuable, but they can not only help programmers write more robust programs, but also the powerful tools of tracking and debugging. It is recommended to constrict the -wall option when compiling the source code with GCC, and gradually cultivate it into a habit, which is helpful for finding a common implicit programming error.
Library dependence
When developing software under Linux, it is relatively few cases that do not use third-party function libraries, which usually needs to be able to complete the corresponding functionality with the support of one or more function libraries. From a programmer's point of view, the library is actually a collection of some header files (.h) and library files (.so or .a). Although most functions under Linux defaults to the / usr / include / directory, the library file is placed in the / usr / lib / directory, but not all the cases are. For this reason, GCC must have its own way to find the header files and library files when compiling.
The GCC uses the search directory to find the required files, and the -i option can add a new directory to the GCC's header search path. For example, if there is a header required for compile time in / home / xiaowp / include / directory, you can use the -i option: # gcc foo.c -i / home / xiaowp / in order to get the GCC to find them smoothly Include -o foo
Similarly, if you use the library files that are not in the standard location, you can add a new directory to the GCC's library file search path via the -l option. For example, if there is a library file libfoo.so when there is a link in the / home / xiaowp / lib / directory, in order to make GCC smoothly, you can use the following command:
# GCC foo.c -l / home / xiaowp / lib --lfoo -o foo
It is worth explaining that the -l option indicates that the GCC goes to the library file libfoo.so. Library files under Linux have an agreement in naming, that is, should start with the three letters of libs, because all library files follow the same specification, so you can save the library name of the library name with the -l option. LIB three letters, that is, GCC automatically goes a file named libfoo.so when the -Lfoo is processed.
Library under Linux is divided into two categories: Dynamic link library (usually in .so end) and static link library (usually .a end), the difference between the two is only running when the program is executed. Dynamically loaded, or is still static when compiling. By default, GCC priorits the dynamic link library when the link is linked, only when the dynamic link is not present, consider using a static link library, if needed, you can add -static options when compiling, forcibly use the static link library. For example, if there is a library file libfoo.so and libfoo.a required when the / home / xiaowp / lib / directory, you can use the following commands when you only use the static link library when the GCC is linked.
# gcc foo.c -l / home / xiaowp / lib -static -lfoo -o foo
Code optimization
The code optimization refers to the compiler by analyzing the source code, finds the part thereof, and then combines it, the purpose is to improve the execution performance of the program. The code optimization function provided by GCC is very powerful, which controls the generation of optimized code by compiling option -on, where n is an integer representing the optimization level. For different versions of GCC, N value range and its corresponding optimization effect may not be exactly the same, and the typical range is from 0 to 2 or 3.
When compiling, use the option -o to tell GCC to reduce the length and execution time of the code, and its effect is equivalent to -o1. Optimized types of optimized at this level depends on the target processor, it generally includes two optimizations of thread jump and derred stack POPS. Options -O2 tells GCC to complete all-O1 level optimization, while providing some additional adjustments, such as processor instruction scheduling. Options -O3 except all-O2 levels, including loop expansion and other optimizations related to processor characteristics. In general, the higher the number, the higher the level, which means that the faster the program is running. Many Linux programmers like to use the -O2 option because it has achieved a more ideal balance point between optimized length, compile time, and code size.
By following the specific examples, feel the GCC's code optimization function, and the procedures are shown in Listing 3.
Listing 3: Optimize.c
#include
INT main (void) {
Double counter;
Double Result;
Double Temp;
For (counter = 0;
COUNTER <2000.0 * 2000.0 * 2000.0 / 20.0 2020;
Counter = (5 - 1) / 4) {
Temp = Counter / 1979;
Result = Counter;
}
Printf ("Result IS% LF / N", Result);
Return 0;
}
First do not add any optimization options:
# gcc -wall Optimize.c -o Optimize
With the Time command provided by Linux, it can be substantially statistics to the time required for the program at runtime:
# Time ./optimize
Result IS 400002019.000000
Real 0m14.942s
User 0m14.940s
SYS 0M0.000S
Next use Optimization options to optimize the code:
# gcc -wall -o Optimize.c -o Optimize
Test the runtime again under the same conditions:
# Time ./optimize
Result IS 400002019.000000
Real 0m3.256s
User 0m3.240s
SYS 0M0.000S
It is not difficult to say that the output of the two execution is not difficult to see that the performance of the program has been improved, which is shortened by the original 14 seconds to 3 seconds. This example is designed specifically for the optimization of GCC, so the execution speed of the program before and after the optimization changes. Although GCC's code optimization is very powerful, as an excellent Linux programmer, we must first strive to write high quality code manually. If the code written is short, and the logic is strong, the compiler will not do more work, even at all, not optimize.
Optimization can bring better execution performance to the procedure, but to avoid optimization code in some occasions:
◆ The higher the optimization level when the program is developed, the longer consumes the time on compile, so it is best not to use the optimization option when developing, only when the software is issued or developed, consider the final generated code. optimization.
◆ Some optimization options increase the volume of the executable code when the resource is limited, and if the program can be applied in the run (such as some real-time embedded devices), do not optimize the code because this The negative impact can produce very serious consequences.
◆ When tracking debugging, some code may be deleted or overwritten, or to achieve better performance, so that tracking and debugging is extremely difficult.
debugging
A powerful debugger not only provides a means of tracking programs, but also helps programmers find solutions to the problem. For Linux programmers, GDB (GNU Debugger) provides a perfect debugging environment for Linux-based software development by using the GCC.
By default, GCC does not insert debug symbols in the generated binary code when compiling, as this will increase the size of the executable file. If you need to generate debug symbol information at compile, you can use the GCC-G or -GGDB option. When the GCC generates a debug symbol, the GCC also uses the grading idea, and the developer can specify how much adding debug information in the code by adding numbers 1, 2 or 3 after the -g option. The default level is 2 (-g2), and the debug information generated at this time includes an extended symbol table, a line number, a partial or external variable information. Level 3 (-g3) contains all debug information in level 2, as well as the macro defined in the source code. Level 1 (-g1) does not contain local variables and debug information related to the line number, so it can only be used for backtracking tracking and stack dump. Backback tracking refers to the function call history during the operation of the program, and the stack dump is a method of saving the program executing the program in the original hex format. The two are often used in debugging means. The debug symbols generated by GCC have universal adaptability, which can be utilized by many modulators, but if GDB is used, then the -ggdb option can contain GDB dedicated debugging information in the generated binary code. The advantage of this approach is that it can be convenient for GDB debugging, but the disadvantage is that other debuggers (such as DBX) cannot be properly debugged. The option -GGDB acceptable debug level and -G are exactly the same, and they have the same impact on the output debug symbols.
It should be noted that the use of any debug option will increase the size of the final generated binaries, while increasing the overhead of the program, so debugging options are usually only used in the development and commissioning phase of the software. The impact of debug options to generate code size can be seen from the following comparison process:
# GCC Optimize.c -o Optimize
# ls Optimize -l
-rwxrwxr-x 1 xiaowp xiaowp 11649 NOV 20 08:53 Optimize (unpatched test option)
# GCC -G Optimize.c -o Optimize
# ls Optimize -l
-rwxrwxr-x 1 xiaowp xiaowp 15889 NOV 20 08:54 Optimize (joining debugging option)
Although the debug option increases the size of the file, in fact, many software in Linux still use debug options in the test version or final release, the purpose is to encourage users to solve their hands when they find problems. A significant feature of Linux.
Below below, how to use the debug symbol to analyze errors, and the program is shown in Listing 4.
Listing 4: Crash.c
#include
Int main (void)
{
INT INPUT = 0;
Printf ("INPUT AN INTEGER:");
Scanf ("% D", Input);
Printf ("THE Integer You Input IS% D / N", Input);
Return 0;
}
Compiling and run the above code, it will generate a segmentation fault as follows:
# gcc -g crash.c -o crash
#./crash
Input an integer: 10
Segmentation Fault
In order to find an error faster, you can use GDB to track debugging, the method is as follows:
# GDB Crash
GNU GDB Red Hat Linux (5.3POST-0.20021129.18RH)
......
(GDB)
When the GDB prompt appears, it indicates that GDB is ready to debug, and now you can start running under the monitor of GDB now through the run command: (GDB) RUN
Starting Program: / Home / XIaowp / Thesis / GCC / Code / Crash
Input an integer: 10
Program received Signal SigSegv, Segmentation Fault.
0x4008576b in _io_vfscanf_internal () from /lib/libc.so.6
Taking a closer analysis of the output results given by GDB, it is not difficult to say due to paragraph errors, indicating that memory operation has problems, and the specific problem is when calling _io_vfscanf_internal (). In order to get more valuable information, you can use the backtrack tracking command backtrace provided by GDB, and the execution results are as follows:
(GDB) BackTrace
# 0 0x4008576b in _io_vfscanf_internal () from /lib/libc.so.6
# 1 0xBffff0c0 in ?? ()
# 2 0x4008e0ba in scanf () from /lib/libc.so.6
# 3 0x08048393 in main () AT CRASH.C: 11
# 4 0x40042917 in __libc_start_main () from /lib/libc.so.6
The front three lines in the output result, it is not difficult to see from the fourth line of the output results, GDB has locked the error to Chao 11 in Crash.c. Check it carefully:
(GDB) Frame 3
# 3 0x08048393 in main () AT CRASH.C: 11
11 scanf ("% d", input);
The frame command provided with GDB can be positioned to the code segment that has occurred, and the value followed by the command can be found in the order of the backtrace command output. Now I have found the error, it should be
Scanf ("% D", Input);
Change to
Scanf ("% D", & input);
You can exit GDB after completion, the command is as follows:
(GDB) quit
The function of GDB is far more than that, it can also check the program, check the memory variable and set breakpoints.
In debugging, you may need to use the intermediate result generated by the compiler. At this time, you can use the -save-temps option to save the GCC to save the code, assembly code, and target code as files. If you want to check if the generated code can improve the performance performance by manual adjustment, the intermediate file generated during the compilation process will be helpful, the specific situation is as follows:
# GCC -SAVE-TEMPS foo.c -o foo
# ls foo *
Foo foo.c foo.i foo.s
Other debug options supported by GCC also include -p and -pg, which adds an analysis (PROFILING) to the finalized binary code. Analysis information is very helpful for finding the performance bottleneck of the program, is a powerful tool to assist Linux programmers to develop high-performance programs. Add the -p option when compiling the PROUSE to add a common profile tool (PROF) to the generated code, and the -pg option generates only the GNU profiling tool (GPROF) can identify statistics.