GCC Wonderful Tour

xiaoxiao2021-03-05  29

GCC Wonderful Tour

GCC wonderful trip (a) Author: Xiaowen Peng issued a document time: 2004.03.22 when developing applications for Linux, use the vast majority of cases are C language, the most important issue facing nearly every Linux programmers are How to 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 # ./hellohello 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 illmode.c: in function` Main ': Illcode.c: 9: ISO C89 Does Not Support `long'illcode.c: 8: Return Type of` main' is not `int '

It should be noted that the -pedant Compilation option does not guarantee that the compiler is fully compatible with the ANSI / ISO C standard, which can only be used to help Linux programmers get 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 illde.c: 8: Warning: Return Type of `main 'is not` int'illcode.c: in function `main': unlcode.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 illde.c-Werror Illcode.c: 8: Warning: Return Type of `main 'is not` Int'illcode.c: in function `main': illmode.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 to make GCCs to find them smoothly:

# GCC foo.c -i / home / xiaowp / include -o foo, if you are using library files that are not standard locations, you can add a new directory to GCC's library file search paths through 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 command:

# gcc foo.c -l / home / xiaowp / lib -static -lfoo -o foo ********************************** *********************************************************** *********** GCC wonderful trip (two) author: Xiaowen Peng issued a document time: 2004.03.22

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 optimized 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 ./optimizeresult IS 400002019.000000Real 0M14.942SUSER 0M14.940ssys 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 ./optimizeresult is 400002019.000000Real 0M3.256SUSER 0M3.240ssys 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 # gcc -g Optimize.c-iptimize # ls Optimize -l-rwxrwxR -x 1 xiaowp xiaowp 15889 NOV 20 08:54 Optimize (joining debugging options)

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 YOUT 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 # ./crashinput an integer: 10SEGMentation Fault

In order to find an error faster, you can use GDB to track debugging, the method is as follows:

# GDB Crashgnu 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 on GDB monitoring through the Run command: (GDB) Runstarting Program: / Home / XIaowp / Thesis / GCC / Code / CrashInput 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 0xBfff0c0 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: 1111 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); changed 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.

Finally, reminded that although GCC allows the addition of debug symbol information while optimization, the optimized code will be a big challenge for debug itself. After optimization, the variables declared and used in the source program are likely to be no longer used. The control flow may suddenly jump to an unexpected place, and the circular statement may become everywhere due to the loop deployment. All of these It will be a nightmare for debugging. It is recommended that it is best not to use any optimized options when debugging, only when the program is optimized when it is finally issued. *********************************************************** ******************************************** GCC wonderful trip (c) author: Xiaowen Peng issued a document time: 2004.04.14 last training grounds described in the compilation of GCC, warning function, library dependencies, code optimization and debugging contents six aspects. This period is the last part of the content.

accelerate

During the process of turning the source code into an executable file, there is a need for many intermediate steps to include pre-processing, compile, assembly, and connections. These processes are actually done by different procedures. In most cases, GCC can complete all background work for Linux programmers, and automatically call the appropriate program for processing.

This has a significant shortcoming, that is, when GCC is handling each source file, it will eventually generate several temporary files to complete the corresponding work, so that the processing speed is slowed in invisible. For example, GCC may need a temporary file to save a pre-processing output, a temporary file to save the output of the compiler, a temporary file to save the output of the assembler, and read and write these temporary files clearly need It takes a certain amount of time. When the software project becomes very large, it will be very heavy.

The solution is to use a more efficient communication method for Linux. It can be used to connect two programs at the same time, where the output of the program will be directly input to another program so that temporary files can be avoided, but more memory needs to be consumed.

The use of the pipe is determined by the GCC -PIPE option during the compilation process. The following command is to improve compilation speed by means of GCC pipe functions:

# GCC -PIPE foo.c -o foo

The difference in compilation time may not be obvious when compiling small projects, and the differences in compile time may not be obvious, but the difference will become very obvious in large projects in the source code.

File extension

In the process of using GCC, users must be familiar with some commonly used extensions and know their meaning. In order to facilitate everyone to learn to use GCC, these extensions are listed here as follows:

.c C original procedure;

.C C original program;

.cc C original program;

.cxx C original program;

.m Objective-c original program;

.i has been pre-treated C original procedure;

.ii has been pre-processed C original procedure;

.S combined language original program;

.S combined language original program;

H. Pre-processing file (header file);

Target file;

.a archive file.

GCC common option

GCC is used as an important compilation environment under Linux, which is powerful, and has a lot of compilation options. In order to facilitate everyone to compile, it will be used herein, and the description of the options is listed as follows:

-c Notification GCC Cancellation Link step, that is, compile the source code and finally generate the target file;

-Dmacro defines the specified macro, allowing it to be inspected through #ifdef in the source code;

-E does not transport to standard outputs without compiling the output; -g3 obtains detailed information about the debugger, it cannot be used in combination with the -O option;

-Idirectory adds a specified directory at the beginning of the included file search path;

-llibrary prompts the link to include the specified library when creating the final executable file;

-O, -O2, and -O3 open the optimized state, this option cannot be combined with the -g option;

-S requires the compiler to generate assembler output from source code;

-v starts all alerts;

-Wall cancels compile operations when an alarm is happened, and the alert will be regarded as an error;

-Wrror cancels the compilation operation when an alert occurs, ie the alarm is used as an error;

-W prohibits all alarms.

summary

GCC is one of the tools that must be mastered when developing programs under Linux. This article makes a brief introduction to GCC, mainly telling how to use GCC compiler, generate warning information, debugging procedures, and speeding up the GCC compilation speed. For all people who wish to enter Linux developers soon, GCC is a starting line for a good Linux programmer.

转载请注明原文地址:https://www.9cbs.com/read-32681.html

New Post(0)