A wonderful tour of GCC

Source: Internet
Author: User
Tags add numbers
A wonderful tour of GCC

**************************************** *************************************

This article by zhengtai Linux http://linux-down.kmip.net collection, sorting, If You Need To reprint, please indicate the source!
This site has a large number of Linux electronic tutorials, software, and technical documents. Welcome to visit! Webmaster aitai QQ: 253222170

**************************************** **************************************

 

Author: Xiao wenpeng published at: 2004.03.22

When developing applications for Linux, the C language is used in most cases. Therefore, almost every Linux programmer is faced with the primary issue of flexible use of the C compiler. Currently, the most common C language compiler in Linux is GCC (GNU Compiler Collection), which is a compilation system that complies with the ansi c standard in the GNU project, compile programs written in C, C ++, Object C, and other languages. Not only is GCC very powerful, but its structure is also extremely flexible. One of the most commendable points is that it can support a variety of 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 using 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 according to their own needs, so as to check or use the output information of the compiler at this stage, or control the final binary file, so that you can prepare for future debugging by adding different numbers and types of debugging code. Like other commonly used compilers, GCC also 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 has made a lot of extensions to the Standard C and C ++ languages, which improves program execution efficiency, helps the compiler to optimize code, and reduces 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
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 work. First, GCC needs to call the Preprocessing Program CPP, which is responsible for expanding the macro defined in the source file, and inserting the content contained in the "# include" statement into it; 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 link the generated target code into 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 to pre-compile. The-e parameter allows GCC to stop the 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 processed accordingly. 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. the I file is considered as the C language source code after preprocessing. Therefore, the above command will automatically skip the preprocessing step and start the compilation process. You can also 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, using GCC can well manage these compilation units. Suppose there is a program consisting of two source files foo1.c and foo2.c. to compile them and generate the executable program Foo, 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. If we look into it, the above command is roughly equivalent to executing the following three commands 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 that need to be compiled, and each source file contains 10000 lines of code. If you use only one GCC command as above to complete the compilation, then GCC needs to re-compile each source file and then connect all the files. Obviously, this wastes a lot of time, especially when a user modifies only one of the files, there is no need to re-compile each file, because many generated target files will not change. To solve this problem, the key is to use GCC flexibly and use tools like make.

Warning function

GCC provides complete error check and warning functions to help Linux programmers write more professional and elegant code. First, read the program shown in Listing 2. The code is poorly written. It is not difficult to pick out a lot of problems after a 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
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 the-pedantic option is added, a warning message 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 get closer and closer to this goal. In other words, the-pedantic option can help programmers find some codes that do not conform to the ANSI/iso c standard, but not all of them, in fact, only those situations that require compiler diagnosis in the ANSI/iso c language standards can be detected 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 is "number-wall". Using this option enables GCC to generate as many warning messages as possible:

# 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 place where errors occur. A good Linux programmer should try to avoid warning information so that his code is always concise, elegant, and robust.

In terms of warning handling, another common compilation option is-werror, which requires GCC to treat all warnings as errors, which is using automatic compilation tools (such as make) is very useful. If the-werror option is included during compilation, GCC stops compilation where warnings are generated, forcing programmers to modify their own code. 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 messages provided by GCC are very valuable. They not only help programmers write more robust programs, but also provide powerful tools for tracking and debugging programs. We recommend that you always use the-wall option when compiling source code with GCC, and gradually cultivate it into a habit, which is helpful for identifying common implicit programming errors.

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 to complete the corresponding functions. From the programmer's perspective, the function library is actually a collection of header files (. h) and library files (. So or.. Although most functions in Linux place header files in the/usr/include/directory by default, and the library files in the/usr/lib/directory, but not all cases are like this. 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 add a new directory to the GCC header file search path. For example, if there is a header file required for compilation in the/home/xiaowp/include/directory, you can use the-I option to make GCC find them smoothly:

# 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 there is a link to the library file libfoo. So in the/home/xiaowp/lib/directory, you can use the following command to make GCC find it smoothly:

# GCC Foo. C-L/home/xiaowp/lib-lfoo-O foo

It is worth explaining that the-L option instructs GCC to connect to the library file libfoo. So. The naming conventions for library files in Linux are as follows: it should start with three letters of Lib. Because all library files follow the same rules, therefore, when you use the-L option to specify the name of the Linked Library file, you can save lib with three letters. That is to say, when GCC processes-lfoo, it automatically links to libfoo. so file.

Library files in Linux are divided into two categories. so) and static link library (usually. end A), the difference between the two is only that the Code required for program execution is dynamically loaded at runtime, or static load at compilation. By default, GCC preferentially uses the dynamic link library when linking. Static Link Library is considered only when the dynamic link library does not exist. If necessary, you can add the-static option during compilation, use a static Link Library. For example, if there is a link in the/home/xiaowp/lib/directory, the library file libfoo is required. so and libfoo. a. To enable GCC to only use the static link library when linking, run 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 re-combines it to improve the execution performance of the program. The code optimization function provided by GCC is very powerful. It controls the generation of optimization code through the compilation option-on, where n is an integer representing the optimization level. 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-O1. The types of optimizations that can be performed at this level depend on the target processor, but they generally include thread jump and deferred stack pops. Option-O2 tells GCC not only to complete all-O1-level optimization, but also to make some extra adjustments, such as processor command scheduling. In addition to completing all-O2-level optimization, option-O3 also includes loop expansion and other optimizations related to the processor features. Generally, the larger the number, the higher the optimization level, and the faster the program runs. Many Linux programmers like to use the-O2 option because it achieves an ideal balance between the optimized length, Compilation 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
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. This example 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 powerful, as an excellent Linux programmer, we must first strive to be able to manually write high-quality code. If the written code is short and logical, 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 optimization options during development. Only when the software release or development ends, to optimize the final generated code.

◆ 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 as some real-time embedded devices ), do not optimize the code, because the negative effects 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. If you need to generate debugging symbol information during compilation, you can use the-G or-ggdb option of GCC. When GCC generates debugging symbols, it also adopts a hierarchical approach, developers can add numbers 1, 2, or 3 after the-G option to specify the number of debugging information added to the Code. The default value is 2 (-G2). The generated debugging information includes extended symbol table, row number, local or external variable information. Level 3 (-G3) contains all debugging information in Level 2 and macros defined in source code. Level 1 (-G1) does not contain local variables and debugging information related to row numbers, so it can only be used for tracing and stack dumping. Tracing refers to the function call history during the running process of the monitoring program. Stack dumping is a method to save the execution environment of the program in the original hexadecimal format, both are commonly used debugging methods.

Debugging symbols generated by GCC are universally adaptive and can be used by many debuggers. However, if GDB is used, you can also use the-ggdb option to include the debugging information dedicated to GDB in the generated binary code. The advantage of this method is that it can facilitate debugging of GDB, but the disadvantage is that other debuggers (such as DBX) may not be able to perform normal debugging. Option-ggdb accepts the same debugging level as-G, which has the same impact on the output debugging symbols.

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 the software development and debugging phase. 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)

Although debugging options increase the file size, many software in Linux still use debugging options for compilation in the test version or even the final release version, this is a distinctive feature of Linux.

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
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, which indicates that the memory operation is faulty, the specific problem occurs when _ io_vfscanf_internal () is called. To obtain more valuable information, you can use the backtrace command backtrace provided by GDB. 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. Check carefully:

(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 found at the beginning of the line in the output result of the backtrace command. The error has been found.

Scanf (/"% d/", input );
Change
Scanf (/"% d/", & input );

After completion, you can exit GDB. The command is as follows:

(GDB) quit

GDB has far more functions than that. It can also track programs, check memory variables, and set breakpoints in one step.

The intermediate results generated by the compiler may be used during debugging. You can use the-save-temps option to enable GCC to save the pre-processing code, assembly code, and target code as files. If you want to check whether the generated code can be manually adjusted to improve the execution performance, the intermediate file generated during the compilation process will be very 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. Profiling is helpful for identifying program performance bottlenecks and a powerful tool to help Linux programmers develop high-performance programs. When the-P option is added during compilation, statistical information that can be recognized by the general profiling tool (Prof) will be added to the generated code, while the-PG option generates only the GNU profiling tool (GPROF) the statistical information that can be identified.

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 variables declared and used in the source program may not be used any more, and the control flow may suddenly jump to an unexpected place, loop statements may become everywhere because of loop expansion. All these are a nightmare for debugging. It is recommended that you do not use any optimization options during debugging. optimization is considered only when the program is finally released.

**************************************** *************************************

This article by zhengtai Linux http://linux-down.kmip.net collection, sorting, If You Need To reprint, please indicate the source!
This site has a large number of Linux electronic tutorials, software, and technical documents. Welcome to visit! Webmaster aitai QQ: 253222170

**************************************** **************************************

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.