When developing applications for Linux, the C language is used in most cases. Therefore, almost every Linux programmer is faced with a primary problem. Flexible use of the C compiler. Currently, the most common C language compiler in Linux is GCC (GNU Compiler Collection), which complies with ansi c in the GNU project. The standard compilation system can compile programs written in C, C ++, Object C, and other languages. GCC is not only powerful, but also flexible in structure. One point is that it can support various languages through different front-end modules, such as Java, Fortran, Pascal, Modula-3 and Ada. Openness, freedom, and flexibility are the charm of Linux, and this is reflected in the GCC through which programmers can better control the entire compilation process. When you use GCC to compile a program, the compilation process can be divided into four stages: ◆ Pre-processing) ◆ Compile (Compiling) ◆ Assembly) ◆ Link (linking) Linux programmers can end GCC at any stage of compilation as needed to check or use the output information of the compiler at this stage, or Finally, the generated binary file is controlled to prepare for future debugging by adding different numbers and types of debugging code. Like compilers, GCC provides flexible and powerful code optimization functions to generate code with higher execution efficiency. GCC provides more than 30 warning messages and three warning levels to help enhance program stability and portability. In addition, GCC also provides The C ++ language has been greatly expanded to improve program execution efficiency, help the compiler to optimize code, and reduce programming workload. Starting with GCC Before learning to use GCC, the following example can help users quickly understand the working principle of GCC and apply it to actual project development. First, enter the code shown in Listing 1 in a familiar Editor: Listing 1: Hello. c # Include <stdio. h> Int main (void) { Printf ("Hello world, Linux programming! /N "); Return 0; } Run the following command to compile and run the program: # GCC hello. C-O hello #./Hello Hello world, Linux programming! From the programmer's point of view, you only need to simply execute a GCC command, but from the compiler's point of view, you need to complete a series of very complicated tasks. First, GCC needs to call the Preprocessing Program CPP, which is responsible for expanding the macro defined in the source file and inserting Then, GCC will call CCL and as to compile the processed source code into the target code. Finally, GCC will call the link program LD to generate the target code. Link to an executable program. To better understand the working process of GCC, you can separate the above compilation process into several steps and observe the running results of each step. The first step is Pre-compile: Use the-e parameter to stop the GCC compilation process after preprocessing: # Gcc-e hello. C-O hello. I If you check the content in the hello. cpp file, you will find that the content of stdio. H is indeed inserted into the file, and other macro definitions that should be preprocessed are also The corresponding processing is done. The next step is to compile hello. I as the target code, which can be done by using the-C parameter: # Gcc-C hello. I-O hello. o By default, GCC regards the. I file as the C language source code after preprocessing. Therefore, the above command will automatically skip the preprocessing step and start the compilation process. Use the-x parameter to let GCC compile from the specified step. The last step is to link the generated target file to an executable file: # GCC hello. O-O hello When the modular design is used for software development, the entire program is usually composed of multiple source files, and multiple compilation units are formed accordingly. GCC can well manage these compilation units. Suppose there is a program consisting of two source files: foo1.c and foo2.c. To compile and Finally, the executable program foo is generated. You can use the following command: # GCC foo1.c foo2.c-O foo If more than one file is processed at the same time, GCC will continue to follow the preprocessing, compilation, and link processes. The following three commands are executed in sequence: # Gcc-C foo1.c-O foo1.o # Gcc-C foo2.c-O foo2.o # GCC foo1.o foo2.o-O foo It is a waste of time to compile a project that contains many source files using only one GCC command. Suppose there are 100 source files in the project. Compilation is required, and each source file contains 10000 lines of code. If you use only one GCC command as above to complete compilation, then GCC needs Each source file is re-compiled and then connected. Obviously, this wastes a lot of time, especially when the user only modifies There is no need to re-compile each file when a file is created, because many generated target files will not change. The key to the problem is to use GCC flexibly, and use tools like make. Warning function GCC includes the complete error check and warning functions, which can help Linux programmers write more professional and elegant code. First read the list 2. This code is poorly written. It is not difficult to pick out a lot of problems after careful check: ◆ The return value of the main function is declared as void, but it should be int; ◆ The GNU syntax extension is used to declare 64-bit integers using long, which does not comply with the ANSI/iso c language standard; ◆ The main function does not call the return statement before termination. Listing 2: illcode. c # Include <stdio. h> Void main (void) { Long long int Var = 1; Printf ("it is not standard C code! /N "); } Next let's take a look at how GCC helps programmers find these errors. When GCC compiles source code that does not conform to the ANSI/iso c language standards, if When the-pedantic option is used, the corresponding warning information is generated when the extended syntax is used: # Gcc-pedantic illcode. C-o illcode 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' Note that the-pedantic compilation option does not guarantee full compatibility between the compiled program and the ANSI/iso c standard. It can only be used to help Linux Programmers are getting closer to this goal. Or in other words, the-pedantic option can help programmers find code that does not conform to the ANSI/iso c standard, But not all. In fact, only those situations that require compiler diagnosis in ANSI/iso c language standards can be discovered and warned by GCC. In addition to-pedantic, GCC also has some other compilation options that can generate useful warning information. Most of these options start with-W, the most valuable of which When the number-wall is reached, it can generate as many warning messages as possible for GCC: # Gcc-wall illcode. C-o illcode 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 cannot be regarded as an error in a strict sense, it is likely to become a false place. A good Linux programmer Do not generate warning information to keep your code concise, elegant, and robust. In terms of warning handling, another common compilation option is-werror, which requires GCC to treat all warnings as errors. (Such as make) is very useful. If the-werror option is included during compilation, GCC will stop compilation where warnings are generated, forcing programmers Your code is modified. The compilation process can be pushed forward only when the corresponding warning information is cleared. The execution is as follows: # Gcc-wall-werror illcode. C-o illcode C0: 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 very valuable. They can not only help programmers write more robust programs, but also track It is recommended that you always use the-wall option when compiling source code with GCC, and gradually cultivate it into a habit, which is common Implicit programming error is very helpful. Library dependency It is rare to develop software in Linux without using third-party function libraries. Generally, one or more function libraries must be supported. From the programmer's point of view, the function library is actually a collection of header files (. h) and library files (. So or. ). Most functions in Linux place the header file in the/usr/include/directory by default, while the library file is in the/usr/lib/directory, but not all This is the case. For this reason, GCC must have its own way to find the required header files and library files during compilation. GCC uses the Directory Search method to find the required files. The-I option can be used to add a new directory to the GCC header file search path. For example, if There are header files required for compilation in the/home/xiaowp/include/directory. To enable GCC to find them smoothly, you can use the-I option: # GCC Foo. C-I/home/xiaowp/include-O foo Similarly, if you use a library file that is not in the standard location, you can use the-L option to add a new directory to the GCC library file search path. For example, if you The library file libfoo. So required when there is a link in the/home/xiaowp/lib/directory. To ensure that GCC can find it smoothly, run the following command: # GCC Foo. C-L/home/xiaowp/lib-lfoo-O foo It is worth explaining that it is the-L option, which instructs GCC to connect to the library file libfoo. So. in Linux, there is a convention when naming the library file, that is, it should The name must start with Lib. Because all library files comply with the same specification, you can save the Lib Three letters, that is, when GCC processes-lfoo, it will automatically link the file named libfoo. So. Library files in Linux are divided into two categories: dynamic link library (usually ended with. So) and static link library (usually ended with. ). The Code required for execution is dynamically loaded at runtime or statically loaded at compilation. By default, the dynamic link library is preferentially used for GCC connection, The static Link Library is considered only when the dynamic link library does not exist. If necessary, you can add the-static option during compilation to force the use of static links. Library. For example, if there is a link to the library files libfoo. So and libfoo. a In the/home/xiaowp/lib/directory, in order to make GCC only use To the static link library, you can use the following command: # GCC Foo. C-L/home/xiaowp/lib-static-lfoo-O foo Code optimization Code optimization means that the compiler analyzes the source code, finds out the part that has not yet reached the optimal value, and then re-combines it to improve the program execution. The code optimization function provided by GCC is very powerful. It controls the generation of optimized code through the compilation option-on. N indicates the optimization level. Integer. For GCC of different versions, the value range of N and its corresponding optimization effects may be different. The typical range is from 0 to 2 or 3. The option-O can be used during compilation to tell GCC to reduce the code length and execution time at the same time. The effect is equivalent to the Optimization class that O1. can perform at this level. Type depends on the target processor, but it generally includes two types of optimization: thread jump and deferred stack pops. Item-O2 tells GCC not only to complete all-O1-level optimization, but also to make some extra adjustments, such as processor command scheduling. Option-O3 In addition to completing all-O2-level optimization, it also includes loop expansion and other optimization work related to the processor features. Generally, the larger the number, the better The higher the level, it also means that the program runs faster. Many Linux programmers prefer to use the-O2 option because it optimizes the length, compilation There is an ideal balance between time and code size. The following describes the GCC code optimization function through a specific instance. The program used is shown in listing 3. Listing 3: optimize. c # Include <stdio. h> 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; } Compile without any Optimization Options: # Gcc-wall optimize. C-o optimize With the time Command provided by Linux, You can roughly calculate the time required for running the program: # Time./optimize Result is 400002019.000000 Real 0m14. 942 s User 0m14. 940 s Sys 0m0. 000 s Next, use the optimization options to optimize the Code: # Gcc-wall-O optimize. C-o optimize Test the running time again under the same conditions: # Time./optimize Result is 400002019.000000 Real 0m3. 256 s User 0m3. 240 s Sys 0m0. 000 s Comparing the output results of the two executions, it is not difficult to see that the program performance has indeed been greatly improved, from 14 seconds to 3 seconds. In this example It is specially designed for the optimization function of GCC, so the execution speed of the program before and after optimization has greatly changed, although the GCC code optimization function is very strong Big, but as a good Linux programmer, first of all, we must strive to be able to manually write high-quality code. If the written code is short and logical Strong, the compiler will not do more work, or even require no optimization at all. Although optimization can bring better execution performance to the program, you should avoid optimizing the Code in the following scenarios: ◆ The higher the optimization level during program development, the longer the compilation time will be spent. Therefore, it is best not to use the optimization option during development, only to soft Finally, the final generated code is optimized only when the release or development process ends. ◆ When resources are limited, some optimization options will increase the size of executable code. If the memory resources that the program can apply for at runtime are very tight (such Some real-time embedded devices), so do not optimize the code, because the negative impact may have very serious consequences. ◆ Some codes may be deleted or rewritten during code optimization during tracking and debugging, or reorganized to achieve better performance, This makes tracking and debugging difficult. Debugging A powerful debugger not only provides programmers with the means to track program execution, but also helps them find a solution to the problem. For Linux programmers, GDB (GNU Debugger) works with GCC to provide a complete debugging environment for Linux-based software development. By default, GCC does not insert debugging symbols into the generated binary code during compilation, because this increases the size of executable files. Generate debugging symbol information during compilation. You can use the-G or-ggdb option of GCC. When GCC generates debugging symbols, it also uses the hierarchical idea. You can add numbers 1, 2, or 3 after the-G option to specify the number of debugging information added to the Code. The default level is 2 (-G2 ). Information includes extended symbol table, row number, local or external variable information. Level 3 (-G3) contains all debugging information in Level 2 and Macro. Level 1 (-G1) does not contain local variables and debugging information related to row numbers. Therefore, it can only be used for tracing and stack dumping. Monitor the function call history of a program during running. Stack dumping is a method to save the program execution environment in the original hexadecimal format. It is a commonly used debugging method. Debugging symbols generated by GCC are universally adaptive and can be used by many debuggers. However, if GDB is used, you can use the-ggdb option. The generated binary code contains debugging information dedicated to GDB. This method facilitates debugging of GDB, but the disadvantage is that it may lead to other The debugger (such as DBX) cannot perform normal debugging. The options-ggdb can accept the same debugging level as-G, and they have the output debugging symbol Same impact. Note that any debugging option will increase the size of the final binary file and increase the overhead of the program during execution, Therefore, debugging options are generally used only in software development and debugging. The impact of debugging options on the size of generated code can be seen from the following comparison process. : # GCC optimize. C-o optimize # Ls optimize-l -Rwxrwxr-x 1 xiaowp 11649 Nov 20 optimize (debug option not added) # Gcc-G optimize. C-o optimize # Ls optimize-l -Rwxrwxr-x 1 xiaowp 15889 Nov 20 optimize (add debugging options) Debugging options increase the file size, but in fact many software in Linux still use debugging options in the test version or even final release version. This is a notable feature of Linux. Compile the code for debugging (compiling code for debugging) To make GDB work normally, you must include debugging information during compilation. debugging information includes the types of each variable in your program and The address ing in the execution file and the line number of the source code. GDB uses this information to associate the source code with the machine code. ◆ Enable the debugging option with the-G option during compilation.
GDB basic commands GDB supports many commands to enable different functions. These commands are loaded from simple files to allow you to check the replay of the called Stack content. Miscellaneous commands. Table 27.1 lists some of the commands you will use when debugging with GDB. For details about how to use GDB, see the guide page of GDB. Table 27.1. Basic gdb commands. Description File to load the executable file to be debugged. Kill to terminate the program being debugged. List lists part of the source code that generates the execution file. Next, execute a line of source code but do not enter the function. Step: execute a line of source code and enter the function. Run to execute the program currently being debugged Quit terminate GDB Watch enables you to monitor the value of a variable, regardless of when it is changed. Break sets breakpoints in the code, which will cause the program to be suspended when it is executed here. Make enables you to re-generate executable files without exiting GDB. Shell enables you to run Unix shell commands without leaving GDB. GDB supports many command editing features similar to those of UNIX Shell programs. you can press the tab key in bash or tcsh to make it complete for you. A unique command. If it is not unique, GDB will list all matching commands. You can also use the mouse key to flip up and down historical commands. The following uses a specific example to describe how to analyze errors using debugging symbols. The program used is shown in Listing 4. Listing 4: crash. c # Include <stdio. h> Int main (void) { Int input = 0; Printf ("input an integer :"); Scanf ("% d", input ); Printf ("the integer you input is % d/N", input ); Return 0; } Compile and run the above Code to generate a serious segment error (segmentation fault) as follows: # Gcc-G crash. C-o crash #./Crash Input an integer: 10 Segmentation fault To locate errors more quickly, you can use GDB for tracking and debugging 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 for debugging. Now you can run the program under GDB monitoring by running 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 After carefully analyzing the output results provided by GDB, it is not difficult to see that the program is aborted due to a segment error, indicating that the memory operation is faulty. The problem is when _ io_vfscanf_internal () is called. To get more valuable information, you can use the tracing Command provided by GDB. Make backtrace. The execution result is 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 Skip the first three rows in the output result. From the fourth row of the output result, it is not difficult to see that GDB has fixed the error to row 11th in crash. C. Now carefully Check: (GDB) frame 3 #3 0x08048393 in main () at Crash. C: 11 11 scanf ("% d", input ); Use the frame Command provided by GDB to locate the code segment with an error. The value following this command can be in the output result of the backtrace command. The first line is found. Now the error is found. Scanf ("% d", input ); Change Scanf ("% d", & input ); After completion, you can exit GDB. The command is as follows: (GDB) quit GDB has many functions, such as one-step tracing, checking memory variables, and setting breakpoints. The intermediate results generated by the compiler may be used during debugging. You can use the-save-temps option to enable GCC to pre-process the code, compile code, and Object The standard code is saved as a file. If you want to check whether the generated code can be manually adjusted to improve the execution performance The generated intermediate file is helpful, as shown in the following figure: # Gcc-save-temps Foo. C-o foo # Ls Foo * Foo. c Foo. I Foo. s Other debugging options supported by GCC include-P and-PG, which add profiling information to the final binary code. It is very helpful to find out the performance bottleneck of the program. It is a powerful tool to help Linux programmers develop high-performance programs. Adding the-P option during compilation will be generated Add the common profiling tool (Prof) to the Code to identify statistics, and the-PG option generates statistics that can only be identified by the GNU profiling tool (GPROF ). Information. Note: Although GCC allows debugging Symbol Information to be added while optimizing, the optimized code will be a great challenge for debugging itself. After the code is optimized, the declared and used variables in the source program may not be used any more, and the control flow may suddenly jump to an unexpected place, loop The statement may become everywhere because of loop expansion. All of this will be a nightmare for debugging. It is recommended that you do not use any Optimization option. optimization is considered only when the program is released. The previous training area introduced six aspects of GCC compilation process, warning function, library dependency, code optimization, and program debugging. Part of the content. Acceleration The process of converting source code into executable files involves many intermediate steps, including preprocessing, compilation, compilation, and connection. In most cases, GCC can complete all background work for Linux programmers and automatically call corresponding programs for processing. One obvious drawback is that when GCC processes each source file, it eventually needs to generate several temporary files to complete the corresponding work, This may cause processing speed to slow down. For example, when GCC processes a source file, it may need a temporary file to save the preprocessing output When the file is used to save the compiler output and a temporary file to save the output of the assembler, it takes some time to read and write these temporary files. When software projects become very large, the cost may become very heavy. The solution is to use a more efficient communication method provided by Linux-pipeline, which can be used to connect two programs at the same time. The output is directly used as the input of another program. This avoids the use of temporary files, but requires more memory during compilation. The pipeline used during compilation is determined by the GCC-pipe option. The following command uses the GCC Pipeline Function to increase the compilation speed: # Gcc-pipe Foo. C-o foo Pipeline is used to compile small projects. The difference in compilation time may not be obvious, but in large projects with many source codes, the difference will become very Obviously. File Extension In the process of using gcc, you must be familiar with some common extensions and understand their meanings. To help you learn how to use GCC The exhibition name is listed as follows: . C original program; . C ++ original program; . Cc c ++ original program; . Cxx C ++ original program; . M objective-C original program; . I the original C program that has been preprocessed; . II the original C ++ program that has been preprocessed; Original program of. s combination language; Original program of. s combination language; . H pre-processing file (header file ); . O target file; . A archive file. Common GCC options As an important compiling environment for C/C ++ in Linux, GCC has powerful functions and many compilation options. To facilitate future compilation It is listed as follows: -C: Notify GCC to cancel the link, that is, compile the source code and generate the target file at the end; -Dmacro defines the specified macro so that it can be verified by # ifdef in the source code; -E is delivered to the standard output without compiling the output of the Preprocessing Program; -G3 gets detailed information about the debugging program, which cannot be used together with the-O option; -Idirectory: add the specified directory at the start point of the file search path; -The llibrary prompts that the linked program contains the specified library when creating the final executable file; -O,-O2, and-O3 enable the optimization status. This option cannot be used together with the-G option; -S requires the Compilation Program to generate the assembler output from the source code; -V starts all alarms; -Wall cancels the compilation operation when an alert is generated, which indicates that the alert is regarded as an error; -Werror: cancel the compilation operation when an alarm occurs, that is, the alarm is treated as an error; -W: Disable all alarms. Summary GCC is one of the tools that must be mastered when developing programs in Linux. This article gives a brief introduction to GCC and mainly describes how to use GCC to compile programs. Generate warning information, debug programs, and speed up GCC compilation. For anyone who wants to enter the ranks of Linux developers as soon as possible, GCC will become A startup line for excellent Linux programmers. |