C is a common programming language that was widely used in the early days of UNIX operating systems. it was first written by Dennis Ritchie of Bell Labs for Unix-assisted development. At the beginning, Unix was written in assembly language and a language called B. since then, C has become the world's most widely used computer language.
The reasons why C is so widely supported in programming are as follows:
It is a very common language. almost any computer you can think of has at least one C compiler that can be used. in addition, its syntax and function libraries are unified on different platforms. This feature is very attractive to developers.
The program written in C runs fast.
C is the system language of all versions of UNIX.
C has made great development in the past two decades. at the end of 1980s, the American National Standards Institute released a C language standard called ansi c. this ensures the consistency of C on different platforms in the future. in 1980s, a C-oriented extension called C ++ emerged. c ++ will be described in another article "C ++ programming.
The available C compiler on Linux is the gnu c compiler. It is based on the programming license of the Free Software Foundation, so it can be freely released. You can find it on the Linux release CD.
Gnu c Compiler
The gnu c compiler (GCC) released with slackware Linux is a fully functional ansi c compatible compiler. if you are familiar with a C compiler on other operating systems or hardware platforms, you will be able to quickly master GCC. this section describes how to use GCC and some of the most common options for GCC compilers.
Use gcc
The basic usage of the GCC compiler. GCC command is usually followed by some options and file names:
GCC [Options] [filenames]
The operation specified by the command line option will be executed on each given file on the command line. The next section describes the options you will most commonly use.
GCC options
GCC has more than 100 compilation options available. many of these options may never be used, but some of the main options will be frequently used. many GCC options include more than one character. therefore, you must specify the respective characters for each option, and, just like most Linux commands, you cannot separate the characters with a group of options. for example, the following two commands are different:
Gcc-p-g test. c
Gcc-PG test. c
The First Command tells GCC to compile test. in C, the profile information is created for the prof command and the debugging information is added to the executable file. the second command only tells GCC to create profiling information for the GPROF command.
When you do not need any options to compile a program, GCC will create (assuming the compilation is successful) a program named. out executable file. for example, the following command will generate. out file:
GCC test. c
You can use the-O compilation option to specify a file name for the generated executable file instead of. out. for example. the C program of C is compiled into an executable file named count. Enter the following command:
Gcc-O count. c
--------------------------------------------------------------------------------
Note: When you use the-O option,-o must be followed by a file name.
--------------------------------------------------------------------------------
GCC also has the compilation option to specify how much the compiler processes. -C indicates that GCC only compiles the source code as the target code and skips the Assembly and connection steps. this option is frequently used because it makes compilation of multiple C Programs faster and easier to manage. the target code file created by GCC is missing. O Extension.
The-s compilation option tells GCC to stop compiling after an assembly language file is generated for C code. the default extension of assembly language files generated by GCC is. s. -E indicates that the compiler only processes the input file. when this option is used, the pre-processor output is sent to the standard output instead of stored in the file.
Optimized items
When you use GCC to compile C code, it will try to complete the compilation at least and make the compiled code easy to debug. easy debugging means that the compiled code has the same execution order as the source code, and the compiled code has not been optimized. there are many options that can be used to tell GCC to generate smaller and faster executable files at the expense of more Compilation Time and easier debugging. the most typical options are-O and-O2.
The-O option tells GCC to optimize the source code. in most cases, these optimizations make program execution faster. -The O2 option tells GCC to generate code as small as possible and as fast as possible. the-O2 option will make compilation faster than-o. however, code execution is usually faster.
In addition to the-O and-O2 optimization options, there are also some low-level options for generating faster code. these options are very special, and it is best to use them only when you fully understand the effects these options will have on the compiled code. for a detailed description of these options, refer to the GCC guide page and type man GCC on the command line.
Debugging and profiling options
GCC supports several debugging and profiling options. Among these options,-G and-PG options are most commonly used.
The-G option tells GCC to generate debugging information that can be used by the GNU Debugger to debug your program. GCC provides a feature that is not available in many other C compilers. in GCC, you can combine-G with-O (to produce optimization code. this is useful because you can debug your code as close as possible to the final product. when you use these two options at the same time, you must be aware that some of your code has been modified by GCC during optimization. for more information about debugging C Programs, see the next section "Debug C Programs with GDB ".
-The PG option tells GCC to add additional code to your program. During execution, GPROF profiling information is generated to show the time consumption of your program. for more information about GPROF, see "GPROF.
Debug the GCC program with GDB
Linux contains a GNU debugging program called GDB. GDB is a powerful debugger used to debug C and C ++ programs. it enables you to observe the internal structure and memory usage of the program while the program is running. the following are some functions provided by GDB:
It enables you to monitor the value of variables in your program.
It enables you to set breakpoints so that the program stops running on the specified code line.
It enables you to execute your code in one row.
Type GDB on the command line and press the Enter key to run GDB. If everything works properly, GDB will be started and you will see similar content on the screen:
GDB is free software and you are welcome to 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.
GDB 4.14 (i486-slakware-linux), copyright 1995 Free Software Foundation, Inc.
(GDB)
After you start GDB, you can specify many options on the command line. You can also run GDB in the following ways:
GDB <fname>
When you run GDB in this way, you can directly specify the program to be debugged. this tells GDB to mount the executable file named fname. you can also use GDB to check a core file generated due to program termination exceptions, or connect it to a running program. you can refer to the gdb guide or Type GDB-H on the command line to get a simple list of instructions on these options.
Compile the code for debugging (compiling code for debugging)
To make GDB work normally, you must make your program contain debugging information during compilation. the debugging information includes the type of each variable in your program, the address ing in the executable file, and the source code line number. 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 complex commands that allow you to check the stack content you are calling. Table 27.1 lists some of the commands you will use when debugging with GDB. for details about how to use GDB, refer to 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 like in bash or tcsh to allow GDB to help you complete 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 History commands.
GDB application example
This section uses an example to teach you how to debug a program with GDB step by step. The program to be debugged is quite simple, but it shows typical applications of GDB.
The program to be debugged is listed below. This program is called greeting, which displays a simple greeting and is listed in reverse order.
# Include <stdio. h>
Main ()
{
Char my_string [] = "Hello there ";
My_print (my_string );
My_print2 (my_string );
}
Void my_print (char * string)
{
Printf ("the string is % s/n", string );
}
Void my_print2 (char * string)
{
Char * string2;
Int size, I;
Size = strlen (string );
String2 = (char *) malloc (size + 1 );
For (I = 0; I <size; I ++)
String2 [size-I] = string [I];
String2 [size + 1] = '/0 ';
Printf ("the string printed backward is % s/n", string2 );
}
Compile it with the following command:
Gcc-O test. c
The following results are displayed when the program is executed:
The string is hello there
The string printed backward is
The first line of output is correct, but the output in the second line is not what we expect. The output we imagine should be:
The string printed backward is ereht olleh
For some reason, the my_print2 function does not work properly. Let's use GDB to see where the problem is. First, enter the following command:
GDB greeting
--------------------------------------------------------------------------------
Note: Remember to open the debugging option when compiling the greeting program.
--------------------------------------------------------------------------------
If you forget to pass the program to be debugged as a parameter when entering the command to GDB, you can use the file command at the gdb prompt to load it:
(GDB) file greeting
This command will load the greeting executable file just as you load it in the gdb command line.
Then you can run greeting using the gdb Run Command. When it is run in GDB, the result will be like this:
(GDB) Run
Starting program:/root/greeting
The string is hello there
The string printed backward is
Program exited with code 041
The output is the same as the running result outside GDB. The question is, why does reverse printing not work? To find out the crux of the problem, we can set a breakpoint after the for statement of the my_print2 function. The specific method is to enter the LIST Command three times at the gdb prompt to list the source code:
(GDB) List
(GDB) List
(GDB) List
--------------------------------------------------------------------------------
Tip: Press enter at the gdb prompt to repeat the previous command.
--------------------------------------------------------------------------------
The output of the first LIST command is as follows:
1 # include <stdio. h>
2
3 main ()
4 {
5 char my_string [] = "Hello there ";
6
7 my_print (my_string );
8 my_print2 (my_string );
9}
10
If you press enter, GDB will execute the LIST command again and give the following output:
11 my_print (char * string)
12 {
13 printf ("the string is % s/n", string );
14}
15
16 my_print2 (char * string)
17 {
18 char * string2;
19 int size, I;
20
Press enter again to list the remaining parts of the greeting program:
21 size = strlen (string );
22 string2 = (char *) malloc (size + 1 );
23 For (I = 0; I <size; I ++)
24 string2 [size-I] = string [I];
25 string2 [size + 1] = '/0 ';
26 printf ("the string printed backward is % s/n", string2 );
27}
Based on the listed source program, you can see that the place where the breakpoint is to be set is in line 24th. At the gdb command line prompt, type the following command to set the breakpoint:
(GDB) Break 24
GDB will make the following response:
Breakpoint 1 at 0x139: file greeting. C, line 24
(GDB)
Enter the Run Command to generate the following output:
Starting program:/root/greeting
The string is hello there
Breakpoint 1, my_print2 (string = 0xbfffdc4 "Hello there") at greeting. C: 24
24 string2 [size-I] = string [I]
You can set an observation point to observe the value of the string2 [size-I] variable to see how an error is generated by typing:
(GDB) Watch string2 [size-I]
GDB will respond as follows:
Watchpoint 2: string2 [size-I]
Now we can use the next command to execute the for loop step by step:
(GDB) Next
After the first loop, GDB tells us that the value of string2 [size-I] Is 'H'. GDB uses the following display to tell you this information:
Watchpoint 2, string2 [size-I]
Old value = 0'/000'
New value = 104 'H'
My_print2 (string = 0xbfffdc4 "Hello there") at greeting. C: 23
23 For (I = 0; I <size; I ++)
This value is expected. the results of subsequent cycles are correct. when I = 10, the value of the expression string2 [size-I] is equal to 'E', the value of size-I is equal to 1, and the last character has been copied to the new string.
If you run the loop again, you will see that no value is allocated to string2 [0], and it is the first character of the new string, because the malloc function initializes them as null characters when allocating memory. therefore, the first character of string2 is a null character. this explains why there is no output when string2 is printed.
It is very easy to correct the problem after finding out the problem. you have to change the offset of the first character written to string2 in the code to size-1 instead of size. this is because the size of string2 is 12, but the starting offset is 0. The characters in the string are offset 0 to offset 10, and the offset 11 is reserved as null characters.
There are many ways to modify the code properly. One is to set a variable that is 1 smaller than the actual size of the string. This is the code for this solution:
# Include <stdio. h>
Main ()
{
Char my_string [] = "Hello there ";
My_print (my_string );
My_print2 (my_string );
}
My_print (char * string)
{
Printf ("the string is % s/n", string );
}
My_print2 (char * string)
{
Char * string2;
Int size, size2, I;
Size = strlen (string );
Size2 = size-1;
String2 = (char *) malloc (size + 1 );
For (I = 0; I <size; I ++)
String2 [size2-I] = string [I];
String2 [size] = '/0 ';
Printf ("the string printed backward is % s/n", string2 );
}
Other C programming tools
The slackware Linux release also includes some C development tools that we haven't mentioned before. This section describes these tools and their typical usage.
Xxgdb
Xxgdb is a graphical interface of GDB Based on the X Window System. xxgdb includes all the features of GDB in the command line version. xxgdb allows you to execute Common commands by pressing the button. the place where the breakpoint is set is also displayed in graphs.
You can run the following command in an xterm window:
Xxgdb
You can use any valid command line options in GDB to initialize xxgdb. In addition, xxgdb also has some special command line options. Table 27.2 lists these options.
Table 27.2. xxgdb command line options.
Description
Db_name specifies the name of the debugger used. The default value is GDB.
Db_prompt specifies the debugger prompt. The default value is GDB.
Gdbinit specifies the name of the command file that initializes GDB. The default value is. gdbinit.
NX tells xxgdb not to execute the. gdbinit file.
Bigicon uses a large icon.
CILS
You can use the following path on the sunsite.unc.edu FTP site:
/Pub/Linux/devel/lang/C/calls.tar. Z
To obtain CILS, some earlier versions of the Linux CD-ROM release is also included. because it is a useful tool, we will introduce it here. if you find it useful, get a copy from BBS, FTP, or another CD-ROM. CILS calls the pre-processor of GCC to process the given source program files, and then outputs the function call tree in these files.
--------------------------------------------------------------------------------
Note: After you log on to your system as a Super User, perform the following steps: 1. decompress and untar files. 2. the sub-directory created after the CD enters calluntar. 3. move the file named CILS to the/usr/bin directory. 4. move the file named calls.1 to the/usr/man/Man1 directory. 5. delete the/tmp/CILS directory. these steps will install the CILS program and its Guide page on your system.
--------------------------------------------------------------------------------
When the call trace result is printed by CILS, the file name of the file where the function is located is given in brackets after the function:
Main [test. C]
If the function is not in the file provided to CILS, and does not know where the called function comes from, only the function name is displayed:
Printf
CILS does not output recursive and static functions. recursive functions are shown as follows:
Fact <recursive in factorial. c>
Static functions are shown as follows:
Total [static in calculate. C]
As an example, we assume that the following program is processed with cballs:
# Include <stdio. h>
Main ()
{
Char my_string [] = "Hello there ";
My_print (my_string );
My_print2 (my_string );
}
My_print (char * string)
{
Printf ("the string is % s/n", string );
}
My_print2 (char * string)
{
Char * string2;
Int size, size2, I;
Size = strlen (string );
Size2 = size-1;
String2 = (char *) malloc (size + 1 );
For (I = 0; I <size; I ++)
String2 [size2-I] = string [I];
String2 [size] = '/0 ';
Printf ("the string printed backward is % s/n", string2 );
}
The following output is generated:
1 main [test. C]
2 my_print [test. C]
3 printf
4 my_print2 [test. C]
5 strlen
6 malloc
7 printf
CILS has many command line options to set different output formats. For more information about these options, refer to the CILS guide page. The method is to type CILS-H on the command line.
Cproto
Cproto reads the C source program file and automatically generates prototype declarations for each function. Using cproto can save you a lot of time to define the function prototype when writing a program.
If you want cproto process the following code:
# Include <stdio. h>
Main ()
{
Char my_string [] = "Hello there ";
My_print (my_string );
My_print2 (my_string );
}
My_print (char * string)
{
Printf ("the string is % s/n", * string );
}
My_print2 (char * string)
{
Char * string2;
Int size, size2, I;
Size = strlen (string );
Size2 = size-1;
String2 = (char *) malloc (size + 1 );
For (I = 0; I <size; I ++)
String2 [size2-I] = string [I];
String2 [size] = '/0 ';
Printf ("the string printed backward is % s/n", string2 );
}
You will get the following output:
/* Test. C */
Int main (void );
Int my_print (char * string );
Int my_print2 (char * string );
This output can be redirected to an inclusion file that defines the function prototype.
Indent
The indent utility is another programming utility included in Linux. in short, this tool produces beautiful indent formats for your code. indent also has many options to specify how to format your source code. for more information about these options, see the indent guide. On the command line, type indent-H.
The following example shows the default output of indent:
Run the C code before indent:
# Include <stdio. h>
Main (){
Char my_string [] = "Hello there ";
My_print (my_string );
My_print2 (my_string );}
My_print (char * string)
{
Printf ("the string is % s/n", * string );
}
My_print2 (char * string ){
Char * string2;
Int size, size2, I;
Size = strlen (string );
Size2 = size-1;
String2 = (char *) malloc (size + 1 );
For (I = 0; I <size; I ++)
String2 [size2-I] = string [I];
String2 [size] = '/0 ';
Printf ("the string printed backward is % s/n", string2 );
}
C code after running indent:
# Include <stdio. h>
Main ()
{
Char my_string [] = "Hello there ";
My_print (my_string );
My_print2 (my_string );
}
My_print (char * string)
{
Printf ("the string is % s/n", * string );
}
My_print2 (char * string)
{
Char * string2;
Int size, size2, I;
Size = strlen (string );
Size2 = size-1;
String2 = (char *) malloc (size + 1 );
For (I = 0; I <size; I ++)
String2 [size2-I] = string [I];
String2 [size] = '/0 ';
Printf ("the string printed backward is % s/n", string2 );
}
Indent does not change the essence of the code, but just changes the appearance of the Code to make it more readable. This is always a good thing.
GPROF
GPROF is a program installed in the/usr/bin directory of your Linux system. It allows you to parse your program to know which part of the program is most time-consuming during execution.
GPROF will tell you the number of calls to each function in the program and the percentage of time each function is executed. This information is useful if you want to improve the performance of your program.
To use GPROF in your program, you must add the-PG option when compiling the program. this will make the program generate a gmon every execution. out file. GPROF uses this file to generate profiling information.
After you run your program and generate the gmon. Out file, you can use the following command to obtain the profiling information:
GPROF <program_name>
The program_name parameter is the name of the program that generates the gmon. Out file.
--------------------------------------------------------------------------------
Tip: GPROF generates a large amount of profiling data. If you want to check the data, you 'd better redirect the output to a file.
--------------------------------------------------------------------------------
F2c and P2c
F2c and P2c are two source code conversion programs. f2c converts Fortran code to C code, and P2c converts Pascal code to C Code. These two programs will be installed when you install GCC.
If you have code written in FORTRAN or Pascal that needs to be rewritten in C, f2c and P2c are very useful to you. the C code generated by these two programs can be directly compiled by GCC without modification.
If the FORTRAN or PASCAL program to be converted is small, you can directly use f2c or P2c without any options. if the program to be converted is large and contains many files, you may need to use some command line options.
Run f2c on a FORTRAN program and run the following command:
F2c my_fortranprog.f
--------------------------------------------------------------------------------
Note: f2c requires that the program to be converted have an extension of. f or a. f.
--------------------------------------------------------------------------------
To replace a PASCAL program with a C program, enter the following command:
P2c my_pascalprogram.pas
The names of the C source code generated by these two programs are the same as those of the original file, but the extension is changed from. f or. Pas to. C.
In TC, CTRL + S save and the suffix is. c
Run in TC, CTRL + S (F2) Save, Suffix:. c