Linux C Development Tool Introduction
2001-05-22 9:49
Publisher: NetBull Readings: 388
There is a lot of software development tools in Linux issues. Many of them are developed for C and C applications. This article describes tools that can be used for C applications and commissioning under Linux. The main purpose of this article is to introduce How to use C compilers and other C programming tools under Linux, not C language programming tutorials.
GNU C compiler
GNU C Compiler (GCC) is a full-featured ANSI C compiler. If you are familiar with a C compiler on other operating systems or hardware platforms, you will be able to master GCC quickly. This section will introduce how to use GCC and some of the most common options for some GCC compilers.
Use GCC
Typically followed by some options and file names using the GCC compiler. The basic usage of the GCC command is as follows:
GCC [Options] [filenames]
The operation specified by the command line option will be executed on the file on the command line. The next section will narrate some of the option you will use.
GCC option
GCC has more than 100 compilation options available. Many of these options you may never use, but some main options will be used frequently. Many of the GCC options include more than one character. So you must be The option specifies its respective hyphens, just like most Linux commands, you cannot follow a set of options after a single hyphen. For example, the following two commands are different:
GCC -P -G Test.c
GCC -PG Test.c
The first command tells the GCC to establish a profile information for the PROF command and add the debug information to the executable file when compiling Test.c. The second command only tells the GCC to establish a profiling information for the gprof command.
When you don't have any option to compile a program, GCC will establish (assuming compile success) a executable file called A.out. For example, the following command will generate a file called A.out in the current directory:
GCC Test.c
You can use the -o compilation option to specify a file name for the generated executable, for example, compile a C program called Count.c as a executable called count, you will enter the following The command:
GCC -O count country.c
-------------------------------------------------- ------------------------------
Note: When you use the -o option, the -o must follow a file name.
-------------------------------------------------- ------------------------------
The GCC also has the compilation options for specifying the compiler processing. The -c option tells the GCC to step only to compile the source code as the target code. This option is very frequent because it makes compiling multiple C procedures Faster and easier to manage. The target code file established by the default when the GCC has an extension.
The -s compilation option tells the GCC to stop compilation language files after the C code is generated. The default extension of the assembly language file generated by the GCC is the .s. -E option indicates that the compiler is only preprocessing the input file. When this When the option is used, the output of the preprocessor is sent to the standard output instead of being stored in the file.
Optimization option
When you use GCC to compile C code, it will try to complete compilation with the least amount of time and make the compiled code easy to debug. Easy to debug means that the compiled code is the same as the source code, and the compiled code has not been passed. Optimization. There are many options that can be used to tell GCC to generate smaller and faster executables on the basis of more compile time and sacrificial easily. These options are -O and -O2 options.
The -o option tells GCC to optimize the source code. These optimizations will make the program execute faster in most cases. -O2 option tells GCC to generate as small and as fast as possible. -O2 option will make compilation The speed is slower than using -O. But the usual code execution speed will be faster.
In addition to the -O and -O2 optimization options, there are some low-level options to generate faster code. These options are very special, and it is best to only be completely understood by these options. What is the compiled code? Detailed description of these options, please refer to the GCC's Guide page, type Man GCC. Debug and profile option on the command line.
GCC supports several commissioning and parsing options. In these options you will most often use the -g and -pg options.
-g option tells GCC to generate debugging information that can be used by the GNU debugger to debug your program. GCC provides a lot of features in many other C compilers, you can make -g and -o in the GCC (produce optimized code ) Use. This is very useful because you can debug your code as possible with the final product as possible. When you use these two options simultaneously, you must know that some code you wrote is already optimized. GCC made changes. For more information on debugging C procedures, please see the "GDB debug C program".
-pg option tells GCC to add additional code in your program, generate GPROF to display the time consumption of your program. For more information on GPROF, please refer to the "GPROF" section.
Debug GCC program with GDB
Linux includes a GNU debugger called GDB. GDB is a powerful debugger for debugging C and C programs. It allows you to observe the internal structure and memory usage of the program at runtime. The following is GDB provided Some features:
It allows you to monitor the value of variables in your program.
It allows you to set breakpoints to stop execution on the specified code line.
It makes you execute your code in a line.
Type GDB on the command line and press Enter to run GDB, if everything is normal, GDB will be started and you will see similar content on the screen:
GNU GDB 5.0
CopyRight 2000 Free Software Foundation, Inc.
GDB IS Free Software, Covered by the gnu general public license, and you are
Welcome to change IT and / or or distribute copies of it under certain conditions.
Type "Show Copying" to see the conditions.
There Is Absolutely No Warranty for GDB. Type "Show Warranty" for Details.
THIS GDB WAS Configured AS "i386-redhat-linux".
(GDB)
When you start GDB, you can specify a lot of options on the command line. You can also run GDB in the following ways:
GDB
When you run GDB in this way, you can specify the program you want to debug. This will tell GDB to load an executable file named FNAME. You can also use GDB to check an Core file that is generated due to an exception termination Or connect with a running program. You can refer to the GDB guide page or type GDB -H on the command line to get a simple list of instructions for these options.
Compilant code for debugging
In order to make GDB work properly, you must make your program contain debugging information when compiling. Debug information contains the type of each variable in your program and the address map in the executable, and the line number of the source code. GDB uses these The information is associated with the source code and the machine code.
Turn on the debug option with the -g option when compiling.
GDB basic order
GDB supports a lot of commands to enable you to achieve different features. These commands are loaded from simple files to the complex commands that allow you to check the contents called the stack content. Table 27.1 lists some of you will use when using GDB debugging Command. Want to know the details of GDB, please refer to the GDB guide page.
Basic GDB command.
Description of the command
File loads the executable you want to debug.
Kill terminates the program being debugging.
List lists a part of the source code that generates the execution file. NexT executes a source code but does not enter the inside of the function.
STEP performs a row source code and enters the inside of the function.
Run executes the current debugged program
Quit termination GDB
Watch allows you to monitor the value of a variable regardless of whether it is changed.
PRINT display the value of the expression
Break sets breakpoints in the code, which will hang it when the program is executed here.
Make allows you to re-generate executables without exiting GDB.
The shell allows you to execute the UNIX shell command without leaving GDB.
GDB supports a lot of command editing features like UNIX shell programs. You can press the Tab key like it in Bash or TCSH to let GDB help you make up a unique command. If you don't have unique, GDB will list all match commands. You You can also flip history commands with cursor keys.
GDB application example
This section teaches you step by step by step. The debugged program is quite simple, but it shows the typical application of GDB.
The program that will be debugged will be listed. This program is called Hello, which shows a simple greeting and listed it with the back sequence.
#include
Static void my_print (char *);
Static void my_print2 (char *);
Main ()
{
CHAR MY_STRING [] = "Hello World!";
MY_PRINT (my_string);
MY_PRINT2 (my_string);
}
void my_print (char * string)
{
Printf ("THE STRING IS% S", String;
}
Void my_print2 (char * string)
{
Char * string2;
Int size, i;
SIZE = Strlen (String);
String2 = (char *) Malloc (SIZE 1);
For (i = 0; i String2 [size - i] = string [i]; String2 [size 1] =; Printf ("THE STRING Printed Backward IS% S", String2); } Compile it with the following command: GCC -G -O Hello Hello.c The following results displayed when this program is executed: ./hello The string is hello world! The String Printed Backward IS The first line of output is correct, but the second line of printing is not what we expect. The output we have envisage should be: The String Printed Backward Is! DLROW OLLEH For some reason, my_print2 functions do not work properly. Let us use GDB to see where there is, type the following command: GDB Hello -------------------------------------------------- ------------------------------ Note: Remember to open the debug option when compiling the Hello program. -------------------------------------------------- ------------------------------ If you forget to pass the program you want to debug as a parameter, you can load it with the file command under the GDB prompt: (GDB) File Hello This command will load the Hello executable as you load it in the GDB command line. At this point you can run Hello with GDB's Run command. When it is running in GDB, the result is about like this: (GDB) RUN Starting Program: / root / hellothe string is Hello World! The String Printed Backward IS Program evted with code 040 This output is the same as the result of running outside GDB. The problem is, why don't you work in the reverse order? In order to find the crux, we can set a breakpoint after the FOR statement of my_print2 function, the specific practice is in the GDB prompt. Type the list command three times, list the source code: (GDB) List (GDB) List (GDB) List -------------------------------------------------- ------------------------------ Tip: Press Enter to return to the car at the GDB prompt. -------------------------------------------------- ------------------------------ The output of the first type of list command is as follows: 1 #include 2 3 static void my_print (char *); 4 static void my_print2 (char *); 5 6 main () 7 { 8 char my_string [] = "Hello World!"; 9 my_print (my_string); 10 MY_PRINT2 (my_string); If you press Enter, GDB will execute a list command, give the following output: 11} 12 13 void my_print (char * string) 14 { 15 Printf ("THE STRING IS% S", String; 16} In one 18 void my_print2 (char * string) 19 { 20 char * STRING2; Pressing a cycle to list the remainder of the Hello program: 21 int size, i; twenty two 23 size = strlen (String); 24 string2 = (char *) Malloc (size 1); 25 for (i = 0; i 26 string2 [size - i] = String [i]; 27 string2 [size 1] =; Twist 29 Printf ("THE STRING Printed Backward IS% S", String2); 30} According to the source program listed, you can see where you want to break points on line 26, type the following command to set the breakpoint at the GDB command line prompt: (GDB) BREAK 26 GDB will make the following response: BreakPoint 1 at 0x804857c: file hello.c, line 26. (GDB) Now type the RUN command, will generate the following output: Starting Program: / root / Hello The string is hello world! Breakpoint 1, MY_PRINT2 (String = 0xBfffffAb0 "Hello World!") At Hello.c: 26 26 string2 [size - i] = String [i]; You can see how the error is generated by setting an observation point of the value of the string2 [size - i] variable, the practice is to type: (gdb) Watch string2 [size - i] GDB will make the following response: Hardware WatchPoint 2: String2 [Size - I] Now you can use the next command to perform the For loop step: (GDB) Next After the first cycle, GDB tells us that the value of string2 [size - i] is `h` GDB tells you this information with the following display: Hardware WatchPoint 2: String2 [Size - I] Old Value = 0 0 New value = 104 h MY_PRINT2 (String = 0xBfffffAb0 "Hello World!") at Hello.c: 25 25 for (i = 0; i This value is expected. The result of the subsequent cycle is correct. When i = 11, the value of the expression string2 [size - i] is equal to ``, size - i is equal to 1, the last one The characters have been copied to the new stroke. If you do the loop again, you will see that there is no value assigned to string2 [0], and it is the first character of the new string, because the malloc function initials them into empty (null) characters when allocating memory So the first character of String2 is empty. This explains why there is no output when printing string2. Now find out where the problem is, correct this error is very easy. You have to change the shift of the first character in String2 in the code to Size - 1 instead of size. This is because String2 size 12, but the start offset is 0, the characters in the string from the offset 0 to the offset 10, the offset amount 11 is a null character. The correction method is very simple. This is the code of this solution: #include Static void my_print (char *); Static void my_print2 (char *); Main () { CHAR MY_STRING [] = "Hello World!"; MY_PRINT (my_string); MY_PRINT2 (my_string); } void my_print (char * string) { Printf ("THE STRING IS% S", String; } Void my_print2 (char * string) { Char * string2; Int size, i; SIZE = Strlen (String); String2 = (char *) Malloc (SIZE 1); For (i = 0; i String2 [size -1 - i] = String [i]; String2 [size] =; Printf ("THE STRING Printed Backward IS% S", String2); } If the program generates a Core file, you can use the GDB Hello Core command to see where the program is wrong. For example, in the function my_print2 (), if you forget to assign memory String2 = (CHAR *) Malloc (size 1); it is likely to be Core Dump. Another C programming tool xxgdb XXGDB is a XXGDB-based graphical interface. XXGDB includes all features on the gdb of the command line. XXGDB enables you to perform a commonly used command by pressing the button. Place the breakpoint is also displayed. You can use the commands below in an XTERM window to run it: xxgdb You can initialize XXGDB with any valid command line option in GDB. In addition, XXGDB also has some unique command line options, and these options are listed in Table 27.2. Table 27.2. Xxgdb command line option. The option description DB_NAME specifies the name of the debugger used, and the default is GDB. DB_PROMPT specifies the debugger prompt, default is GDB. GDBINIT specifies the file name of the initialization of the command file of GDB, default is .gdbinit. NX tells XXGDB does not execute .Gdbinit file. Bigicon uses a large icon. Calls You can use the following path in the Sunsite.Unc.edu FTP site: /Pub/linux/devel/lang/calls.tar.z To get Calls, some old version of the Linux CD-ROM release is also included. Because it is a useful tool, we also introduce here. If you think useful, from BBS, FTP, or another CD -ROM Lote. Calls Calls the GCC's preprocessor to process the given source program file, then output the function call the tree in these files. Note: Install Calls on your system, perform the following steps after you log in as yours: 1. Unzip and Untar files. 2. The CD enters the subdirectory established after Calls Untar. 3. Move the name called Calls to / usr / bin directory. 4. Move the file called calls.1 to the directory / usr / man / man1. 5. Delete the / tmp / calls directory. These steps will load your calls and its guide page to load your System on the system. -------------------------------------------------- ------------------------------ When Calls prints a tracking result, it gives the file name of the file in the function behind the function after the function: Main [hello.c] If the function is not in the file given to the calls, calls don't know where the call is called, only the name of the function is displayed: PRINTF Calls does not output the recursive and static function. The recursive function is displayed below: FACT <<< Recursive in Factorial.c >>> Static function is like this: Total [static in caverculate.c] As an example, assume that the following programs are treated with Calls: #include Static void my_print (char *); Static void my_print2 (char *); Main () { CHAR MY_STRING [] = "Hello World!"; MY_PRINT (my_string); MY_PRINT2 (my_string); MY_PRINT (my_string); } void count_sum () { INT I, SUM = 0; For (i = 0; i <1000000; i ) SUM = I; } void my_print (char * string) { count_sum (); Printf ("THE STRING IS% S", String; } Void my_print2 (char * string) { Char * string2; Int size, i, sum = 0; count_sum (); SIZE = Strlen (String); String2 = (char *) Malloc (SIZE 1); For (i = 0; i String2 [size] =; For (i = 0; i <5000000; i ) SUM = I; Printf ("The String Printed Backward IS% S", String2); The following output will be produced: 1 __underflow [hello.c] 2 main 3 my_print [hello.c] 4 count_sum [hello.c] 5 Printf 6 my_print2 [hello.c] 7 count_sum 8 Strlen 9 malloc 10 Printf Calls has a lot of command line options to set different output formats, please refer to the Calls guide page for more information on these options. Method is to type Calls -h on the command line. CallTree CallTree is similar to calls, and the output function calls the tree map, there are other detailed information. You can use the following path from the SunSite.Unc.edu FTP site: /pub/linux/devel/lang/c/calltree.tar.gz Get CallTree. CPROTO CPROTO reads the C source file and automatically generates prototypes for each function. Use CPROTO to save a lot of time to define a function prototype when writing programs. If you let CProto processes the following code (CPROTO Hello.c): #include Static void my_print (char *); Static void my_print2 (char *); Main () { CHAR MY_STRING [] = "Hello World!"; MY_PRINT (my_string); MY_PRINT2 (my_string); } void my_print (char * string) { Printf ("THE STRING IS% S", String; } Void my_print2 (char * string) { Char * string2; Int size, i; SIZE = Strlen (String); String2 = (char *) Malloc (SIZE 1); For (i = 0; i String2 [size -1 - i] = String [i]; String2 [size] =; Printf ("THE STRING Printed Backward IS% S", String2); } You will get the following output: / * Hello.c * / INT main (void); INT my_print (char * string); INT my_print2 (char * string); This output can be redirected to a defined function prototype. Indent The Indent utility is another programming utility included in Linux. This tool simply produces a beautiful indentation format for your code. Indenter has many options to specify how to format your source code. These options For more information, please see the Indent's Guide page, type indent -h on the command line. The following example is the default output of Indent: Run the previous C code before: #include Static void my_print (char *); Static void my_print2 (char *); Main () { CHAR MY_STRING [] = "Hello World!"; MY_PRINT (my_string); MY_PRINT2 (my_string); } void my_print (char * string) { Printf ("THE STRING IS% S", String; } Void my_print2 (char * string) { CHAR * STRING2; INT SIZE, I; SIZE = Strlen (String); String2 = (char *) Malloc (SIZE 1); For (i = 0; i String2 [size] =; Printf ("THE STRING Printed Backward IS% S", String2); } Code running in Indent: #include Static void my_print (char *); Static void my_print2 (char *); Main () { CHAR MY_STRING [] = "Hello World!"; MY_PRINT (my_string); MY_PRINT2 (my_string); } Void MY_PRINT (Char * String) { Printf ("THE STRING IS% S", String; } Void MY_PRINT2 (Char * String) { Char * string2; Int size, i; SIZE = Strlen (String); String2 = (char *) Malloc (SIZE 1); For (i = 0; i String2 [SIZE - 1 - I] = String [i]; String2 [size] =; Printf ("THE STRING Printed Backward IS% S", String2); } Indenter does not change the substance of the code, but only change the appearance of the code. Make it more readable, which is always a good thing. GPROF GPROF is a program installed in the / usr / bin directory of your Linux system. It makes you analyzing your program to know which part of the program is performed. GPROF will tell you the number of times each function called and the time to perform time when performing each function. If you want to improve your program performance, this information is very useful. In order to use GPROF on your program, you must add -pg options when compiling. This will cause the program to generate a file called GMon.out when executed. Gprof generates a profiling information with this file. After you run your program and generate the gmon.out file, you can use the following command to obtain an analysis: GPROF The parameter program_name is the name of the program that produces the GMON.out file. In order to explain the problem, the function count_sum () is added to the program to consume the CPU time, the program is as follows #include Static void my_print (char *); Static void my_print2 (char *); Main () { CHAR MY_STRING [] = "Hello World!"; MY_PRINT (my_string); MY_PRINT2 (my_string); MY_PRINT (my_string); } void count_sum () { INT I, SUM = 0; For (i = 0; i <1000000; i ) SUM = I; } void my_print (char * string) { count_sum (); Printf ("THE STRING IS% S", String; } Void my_print2 (char * string) { Char * string2; Int size, i, sum = 0; count_sum (); SIZE = Strlen (String); String2 = (char *) Malloc (SIZE 1); For (i = 0; i String2 [size] =; For (i = 0; i <5000000; i ) SUM = I; Printf ("THE STRING Printed Backward IS% S", String2); } $ GCC -PG -O Hello Hello.c $ ./hello $ GPROF HELLO | More The following output will be produced Flat Profile: Each Sample Counts as 0.01 Seconds. % Cumulative Self Self Total Time Seconds Seconds Calls US / Call US / Call Name 69.23 0.09 0.09 1 90000.00 103333.33 MY_PRINT2 30.77 0.13 0.04 3 13333.33 13333.33 count_sum 0.00 0.13 0.00 2 0.00 13333.33 MY_PRINT % Executive Time occupied by this function Percentage of TIME execution time Cumulative Cumulative Sumulation Time Execution This function takes place Seconds (including this function calling other functions) Self Execute the time spent this function Seconds (calling other functions) is not calculated) Calls call Self each this functions cost this function US / Call Total Decrease this function, add other functions US / Call costs microsecond times Name function name As can be seen from the above data, the execution my_print () function itself does not cost what time, but it calls the count_sum () function, so the total number of seconds is 0.13. Tip: The profiling data generated by GPROF is very large. If you want to check this data, it is best to redirect the output to a file. Source: LinuxAid