Can you imagine using a private compiler with closed source code to compile free software? How do you know that the compiler is on you?
What is included in the executable file? Various backdoors and Trojans may be added. Ken Thompson is
The famous hacker, he compiled a compiler. When the compiler compiles itself, it is in the 'login' program.
Leave a backdoor and a permanent Trojan. Fortunately, we have GCC. When you perform configure; make;
During make install, GCC has done a lot of heavy work behind the scenes. How can we make GCC work for us?
What about it? We will start to write a card game, but we just want to demonstrate the functionality of the compiler, so
Streamline the code as much as possible. We will start from scratch step by step to understand the compilation process and understanding
What needs to be done to make executable files, in what order. Let's take a look at how to compile C Programs
And how to use the compilation options to make GCC work according to our requirements. Steps (and tools used) are as follows:
Below: Pre-compilation (GCC-E), compilation (GCC), Assembly (AS), and connection (LD ).
Start...
First, we should know how to call the compiler. In fact, this is very simple. From the famous
The first C program starts. (Forgive me ).
# Include <stdio. h>
Int main ()
{
Printf ("Hello world! /N ");
}
Save this file as game. C. You can compile it in the command line:
GCC game. c
By default, the C compiler generates an executable file named A. Out. You can enter the following
Run the following command:
A. Out
Hello World
Each time a program is compiled, the new A. out will overwrite the original program. You cannot know which program is used to create
A. Out is created. We can use the-O compilation option to tell GCC that we want to call the executable file
What is the name. We will call this program
Game, we can use any name, because C has no naming restrictions like Java.
Gcc-O game. c
./Game
Hello World
So far, we are far from a useful program. If you are frustrated, you can think about it.
I think we have compiled and run a program. Because we add features for this program,
So we must ensure that it can run. It seems that every programmer who just started learning programming wants to compile it all at once.
A 1000-line program, and then modify all the errors at a time. No one, I mean no one, can do it
This. You should first compile a small program that can be run, modify it, and then let it run again. This works.
Limit the number of errors you have modified at a time. In addition, You know what changes have been made to make the program unable to run,
So you know where to focus. This prevents you from writing
It can also be compiled, but it cannot run. Remember to pass
The compiled program does not mean it is correct.
Next, write a header file for our game. The header file sets the data type and function declaration
. This ensures consistency of data structure definitions so that each part of the program can be in the same way
View everything.
# Ifndef deck_h
# Define deck_h
# Define decksize 52
Typedef struct deck_t
{
Int card [decksize];
/* Number of cards used */
Int dealt;
} Deck_t;
# Endif/* deck_h */
Save the file as deck. h. Only. c files can be compiled, so we must modify game. C. In
Write # include "deck. H" in the second line of game. C ". Write deck_t deck; in the row 5th ;. To
Make sure that we didn't make a mistake and re-compile it.
Gcc-O game. c
If there is no error, there is no problem. If the compilation fails, modify it until it passes.
.
Pre-compile
How does the compiler know about deck_t?
What is the type? Because during pre-compilation, it actually copies the "deck. H" file to "game.
C "file. The pre-compilation instructions in the source code are prefixed. You can add-E after GCC to select
To call the pre-compiler.
Gcc-e-o game_precompile.txt game. c
WC-l game_precompile.txt
3199 game_precompile.txt
There are almost 3200 rows of output! Most of these files are from stdio. h.
File, our statement is also there. If you do not need the-O option to specify the output file name,
It is output to the console. The pre-compilation process provides great flexibility for the code by completing three main tasks.
1. Copy the "include" file to the source file to be compiled.
2. Replace "Define" text with actual values.
3. Replace the macro at the place where the macro is called.
This enables you to use Symbolic constants in the entire source file (that is, decksize is used to represent cards on a pay card ).
Number), and the symbolic constant is defined in one place. If its value changes, all operators
Constant can be automatically updated. In practice, you almost do not need to use the-e option separately,
Let it send the output to the compiler.
Compile
As an intermediate step, GCC translates your code into an assembly language. It must do this, and it must
Analyze your code to find out what you want to do. If you make a syntax error, it will tell
You, so the compilation will fail. People sometimes misunderstand this step as a whole process. However
There is a lot of work to be done by GCC.
Assembly
As converts the assembly language code to the target code. In fact, the target code cannot run on the CPU, But it
It is very close to completion. Compiler option-C converts the. c file to a target file with the. O Extension
. If we run
Gcc-C game. c
We automatically created a file named game. O. Here we have encountered an important problem. Me
You can use any. c file to create a target file. As we can see below
In the subsequent steps, we can combine these target files into executable files. Let's continue to introduce our example
Child. Because we are writing a card game, we have defined one card as deck_t.
Write a shuffles function. This function accepts a pointer to the deck type and returns a random value.
Card load type. It uses 'drawn'
Array tracking records that have been used. This array with decksize elements can prevent us from
Use a card again.
# Include <stdlib. h>
# Include <stdio. h>
# Include <time. h>
# Include "deck. H"
Static time_t seed = 0;
Void shuffle (deck_t * pdeck)
{
/* Keeps track of what numbers have been used */
Int drawn [decksize] = {0 };
Int I;
/* One Time initialization of Rand */
If (0 = seed)
{
Seed = Time (null );
Srand (SEED );
}
For (I = 0; I <decksize; I ++)
{
Int value =-1;
Do
{
Value = rand () % decksize;
}
While (drawn [value]! = 0 );
/* Mark value as used */
Drawn [value] = 1;
/* Debug statement */
Printf ("% I/N", value );
Pdeck-> card [I] = value;
}
Pdeck-> dealt = 0;
Return;
}
Save the file as shuffle. C. We added a debugging statement to the Code to run
Line number. This does not add functionality for our program, but now it is off
Key moment. Let's see what happened. Because our game is still in its infancy, we have no difference
To determine whether our function has implemented the required functions. Using the printf statement, we
So that we can know exactly what is happening now, so that we can know that the card has been
Washed. After we are satisfied with its work, we can delete the line of statements from the code.
. This debugging program looks rough, but it uses the least statement to complete the debugging task. To
Then we will introduce more complex debuggers.
Pay attention to two issues.
1. We use the address transfer method to pass Parameters. You can see from the '&' operator. This variable
The machine address of is passed to the function, so the function can change the value of the variable itself. You can also use global variables.
Write programs, but use as few global variables as possible. Pointer is an important part of C. You
We should fully understand it.
2. We use function calls in a new. c file. The operating system always looks
Function and start execution from there. Shuffle. C does not have the 'main' function, so it cannot be compiled as a standalone
Executable files. We must associate it with another program that has the 'main' function and calls 'shuffle '.
In sequence.
Run commands
Gcc-C shuffle. c
Make sure that it creates a new file named shuffle. O. Edit the game. c file. In row 7th
After the deck variable of the deck_t type is declared, add the following line:
Shuffle (& deck );
Now, if we create an executable file as before, we will get an error
Gcc-O game. c
/Tmp/ccmihnjx. O: In function 'main ':
/Tmp/ccmihnjx. O (. Text + 0xf): Undefined reference to 'shuffle'
Collect2: LD returned 1 exit status
The compilation is successful because our syntax is correct. However, the connection fails because we do not
Tell the compiler where the 'shuffle' function is. So what is connection? How can we tell Compilation
Where can I find this function?
Connection
Connector lD, use the following command to accept the target file created previously by AS and convert it to Executable
Row files
Gcc-O game. O shuffle. o
This will combine the two target files and create an executable file game.
The connector finds the shuffle function from the shuffle. O target file and includes it into the executable file.
The real benefit of the target file is that if we want to use that function again, all we need to do is package
Include the "deck. H" file and connect the target shuffle. o file to the new executable file.
Code reuse like this often happens. Although we have not compiled the previous Code called as a debugging statement
Printf function, but the connector can be found from the files contained in the # include <stdlib. h> statement.
And connect the target code stored in the C library (/lib/libc. so.6. This
So that we can use the functions of other people who have been able to work correctly, only focus on the problems we want to solve
. This is why the header file generally only contains data and function declaration, without the function body. Generally, you
You can create a target file or function library for the connector to connect to the executable file. Our code may
A problem occurs because we didn't put any function declaration in the header file. To make sure everything goes well, I
What else can we do?
Two other important options
-Wall option can enable all types of syntax warnings to help us determine that the code is correct and
And achieve portability as much as possible. When we use this option to compile our code, we will see the following
Warning:
Game. C: 9: Warning: Implicit declaration of function 'shuffle'
This makes us know that there is still some work to be done. We need to add a line of code to the header file to tell
The compiler has everything to do with the shuffle function so that it can perform necessary checks. It sounds like a sort
But in this way, we can separate the definition and implementation of the function so that we can use me anywhere.
All you need to do is include the new header file and connect it to our target file. Lower
Add this row to deck. h.
Void shuffle (deck_t * pdeck );
This eliminates the warning information.
Another common compiler option is the optimization option-o #(-O2 ). This tells the compiler what you need
Level optimization. The compiler has a complete set of techniques to make your code run faster. For
You may not be aware of the differences, but it can be greatly improved for large programs.
Running Speed. You will often encounter it, so you should know what it means.
Debugging
As we all know, code compilation does not mean it works as required. You can
Run the following command to verify whether all numbers are used.
Game | sort-N | less
And check whether there are any omissions. What should we do if there is a problem? How can we go deep into the bottom layer
Looking for errors?
You can use the debugger to check your code. Most releases provide the famous Debugger GDB. For example
If many command line options make you feel at a loss, you can use one of
Good front-end tool kdbg. Other front-end tools are similar. To start debugging,
You can select File-> executable and find your game program. When you press F5 or select
Execution-> when running from the menu, you can see the output in another window. What's going on? There
Window. Don't worry. There is no problem with kdbg. The problem is that we are
The row file does not contain any debugging information, so kdbg cannot tell us what happened internally. Compile
You can add necessary debugging information to the target file. You must use this option to compile the target file.
(The extension is. O), so the command line is:
Gcc-g-C shuffle. C game. c
Gcc-g-o game. O shuffle. o
This puts the hook into an executable file so that GDB and kdbg can indicate the running condition. Debugging is
An important technology is worth your time to learn how to use it. The method that the debugger helps programmers is that it can
Set "breakpoint" in source code ". Now you can right-click the line generation that calls the shuffle function
Code, and try to set the breakpoint. A small red circle appears on the side of the line. Now when you press F5
The program stops running on that line. Press F8 to jump into the shuffle function. Oh, now we can
The code in Shuffle. C is displayed! We can control the program execution step by step and see the actual
What happened. If you pause the cursor on a local variable, you can see the content of the variable. Good
. This is much better than the printf statement, isn't it?
Summary
This article describes how to compile and debug C Programs. We have discussed the steps taken by the compiler,
And what options should be passed to GCC for the compiler to do this. We briefly describe the connection
Finally, the debugger is introduced. It takes a lot of effort to really understand what you are doing.
I hope this article will help you get started correctly. You can use the GCC, As, and ld man and
Find more information in info page.
You can write your own code to learn more. As an exercise, you can use this article's card game
Compile a 21-point game. Then you can learn how to use the debugger. Use kdbg of GUI
It is easier to start. If you only add a few features at a time, you will soon be able to complete it. Remember
, Be sure to keep the program running!
To write a complete game, you need the following content:
* Definition of a card player (that is, you can define deck_t as player_t ).
* A function that sends a certain number of cards to a specified player. Remember to increase the number of licensed cards in order to know which cards are available. Remember the number of cards in the player's hands.
* Some interactions with users ask if the player needs another card.
* A function that prints cards in the player's hands. Card equals value % 13 (numbers 0 to 12 ),
Suit is equal to value/13 (numbers are 0 to 3 ).
*
A function that determines the value in the player's hands. The value of ACE is zero and can be equal to 1 or 11. King
Value is 12 and can be equal to 10.