GCC Rules Do you want to build free software with a private compiler with a closed source code? How do you know what the compiler has added in your executable? Various back doors and Trojans may be added. Ken Thompson is a famous hacker, who wrote a compiler, when the compiler compiles yourself, leave the back door and permanent Trojan in the 'login' program. Please read the description of this masterpiece here. Fortunately, we have GCC. When you use configure; make INSTALL, GCC has made a lot of heavy work behind the scenes. How can I get GCC work for us? We will start writing a card game, but we are just to demonstrate the function of the compiler, so we will streamline the code as much as possible. We will do step by step in step to understand the compilation process, understand what to do in order to make executive files, and do it in any order. We will look at how to compile the C program, and how to use the compilation option to make GCC work according to our requirements. Steps (and tools used) are as follows: Precommination (GCC -E), Compilation (GCC), Compilation (AS), and Connection (LD).
Start ... First, we should know how to call the compiler. In fact, this is simple. We will start from the famous first C program. (Please forgive me).
#include
INT main () {Printf ("Hello World!");
Save this file as Game.c. You can compile it under the command line:
GCC Game.c
By default, the C compiler will generate an executable file named A.out. You can type it as follows: a.outhello world
When each compiler, the new A.out will overwrite the original program. You can't know which program creates A.out. We can tell GCC what is the name of the executable file by using the -o compilation option. We will call this program for GAME, we can use any name, because C does not have a naming limit like Java. GCC -O Game Game.c
GameHello World
So far, we are far away from a useful program. If you feel frustrated, you can think about we have compiled and run a program. Because we will add features to this program, we must ensure that it can run. It seems that each of the programs who have just started learning programming, they see a 1000-row program, and then modify all errors. No one, I said no one, I can do this. You should first compile a small program that can run, modify it, and then let it run again. This can limit the number of errors you modified once. In addition, you know which modifications just do have made the program can't run, so you know where you should put your attention. This prevents such a situation: you think what you have written should work, it can also be compiled, but it is not running. Please remember that the program that can be compiled does not mean it is correct.
Next, write a header file for our game. The header file sets the data type and function declaration to one. This ensures consistency of data structural definitions so that every part of the program can treat everything in the same way.
#ifndef deck_h # define deck_h
#define decksize 52
Typedef struct deck_t {int CARD [DECKSIZE]; / * NUMBER OF CARDS USED * / INT DEALT;
#ENDIF / * DECK_H * /
Save this file as deck.h. You can only compile .c files, so we must modify Game.c. On the 2nd line of Game.c, write the #include "deck.h". Deck_t deck on the 5th. In order to ensure that we didn't make mistakes, re-compiled it once. GCC -O Game Game.c
If there is no error, there is no problem. If compiled cannot pass, then modify it until it can be passed.
How do the pre-compilation compiler know what the dec kit is the type? Because it actually copied the "dec k" file to the "Game.c" file during the pre-compiled period. The pre-compiled instruction in the source code is prefixed as "#". You can call the precompiler by adding the -e option after GCC.
GCC-E-O Game_Prec --l Game_Precompile.txt 3199 Game_Precompile.txt
Almost 3200 lines of output! Most of them come from stdio.h contains files, but if you view this file, our statement is there. If you don't use the -o option to specify the output file name, it outputs it to the console. The pre-compiled process has given a lot of flexibility by completing three main tasks. Copy the "include" file to the source file to be compiled. Use the actual value to replace "define" text. Macro replacement in the call to the macro. This allows you to use symbol constants throughout the source file (ie use defksize to repay the number of cards in one payment), and the symbol constant is defined in one place. If its value changes, all use symbol constants Places can be automatically updated. In practice, you almost do not need to use the-E option alone, but let it transfer the output to the compiler.
Compile as a middle step, GCC translates your code into assembly language. It must do this, it must figure out what you want to do by analyzing your code. If you make a grammatical error, it will tell you that compiled is failed. People sometimes misunderstand this step as the whole process. However, there are still many jobs to do GCC.
Compilation AS converts assembly language code into target code. In fact, the target code cannot be run on the CPU, but it is already close to the completion. The compiler option -c converts the .C file to the target file of .o as the extension. If we run
gcc -c game.c
We automatically created a file called Game.o. Here we have encountered an important issue. We can create a target file with any .c file. As we can see below, in the connection step we can combine these object files into executables. Let us continue to introduce our example. Because we are writing a card game, we have already defined a pay card as deck_t, we will write a shuffle function. This function accepts a pointer to the DECK type and loads a random card into the DECK type. It uses 'DRAWN' array tracking records that those cards have been used. This array with Decksize elements can prevent us from repeating a card.
#include
Static Time_t seed = 0;
Void shuffle (deck_t * pdeck) {/ * Keeps TRACK OF WHAT DRAWN [DECKSIZE] = {0}; int i;
/ * One time initialization of rand * / if (0 == seed) {seed = Time (null); SRAND (SEED);} for (i = 0; i / * Debug Statement * / Printf ("% i", value); pdeck-> card [i] = value;} PDECK-> DEALT = 0; Return;} Save this file as shuffle.c. We added a debug statement in this code to run the generated grade. This doesn't add functions to our programs, but now I am a crucial moment, let's see what happened. Because our game is still in the primary stage, we don't have any other way to determine if our functions have realized our requirements. Using that printf statement, we can accurately know what happened now, so that we know that the card has been washed before starting the next phase. After we feel satisfied with its work, we can delete the line of statements from the code. This debugger technology looks rough, but it completes the debug task using the least statement. In the future, we will introduce more complex debuggers. Please pay attention to two problems. We pass parameters in an addressing, you can see from '&' (take address) operators. This is passed to the function of the machine address, so the function can change the value of the variable. You can also use global variables to write programs, but you should use less global variables as little as possible. The pointer is an important part of C, and you should fully understand it. We use function calls in a new .c file. The operating system is always looking for functions called 'main' and starts there. There is no 'main' function in shuffle.c, so you cannot compile an independent executable. We must combine it with another program with the 'main' function and call 'shuffle'. Run command gcc -c shuffle.c And make sure it created a new file called shuffle.o. Edit the Game.c file, on line 7, after the Deck_t type variable decker declaration, add the following line: shuffle (& deb); Now, we will get an error GCC -O Game Game.c. / TMP/ccmihnjx.o: in function `main ': / tmp / ccmihnjx.o (.text 0xf): undefined reference to` shuffle'collect2: ld returned 1 exit status Compile success, because our syntax is correct. But the connection step failed because we didn't tell the compiler 'shuffle' function. So what is the connection? How do we tell the compiler to find this function? Connect the connector LD, use the following command, accept the target file created by AS and convert it to an executable GCC -O Game Game.o shuffle.o This will combine two target files and create executable files. The connector locates the shuffle function from the shuffle.o target file and includes enters the executable. The real benefit of the target file is that if we want to use that function again, what we have to do is to include "dec k" files and connect the shuffle.o target file to a new executable. The code reuse like this happens. Although we did not write a Printf function called in front as a debug statement, the connector could find its declaration from the files we included with a #include The other two important options -wall options can open all types of syntax warnings to help us determine that the code is correct and minimizes portability. 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 lets us know that there are still some jobs to do. We need to join a line of code in the header file to tell the compiler about everything about the shuffle function, so that it can do the necessary checks. It sounds like a scil, but doing this can separate the definition of the function, so that we can use our functions anywhere, just contain new headers and connect it to our target file. Yes. Let's add this line to Deck.h. Void shuffle (DECK_T * PDECK); This will eliminate the warning information. Another commonly used compiler option is an optimization option -O # (ie -o2). This is what level optimization you need to tell the compiler. The compiler has a set of skills to make your code run faster. For our apparatus, you may not pay attention to the difference, but for large programs, it can greatly improve the running speed. You will often touch it, so you should know what it means. Debug We all know that the code has been compiled and does not mean that it will work according to us. You can use the following command to verify that all numbers have been used. Game | Sort - N | Less And check if there is any omission. What should we do if there is a problem? How can we go deep into the underlying to find errors? You can check your code using the debugger. Most releases provide a famous debugger: GDB. If those of the many command line options make you feel awful, then you can use a good front-end tool KDBG with KDE. There are also some other front-end tools, they are all similar. To start debug, you can choose File-> Executable and find your Game program. When you press the F5 key or select Execution-> From the menu, you can see the output in another window. what happened? In that window, we can't see anything. Don't worry, KDBG has no problem. The problem is that we did not join any debugging information in the executable, so KDBG could not tell us what happened within. The compiler option -g can add the necessary debug information to the target file. You must use this option to compile the target file (extension .o), so command is configured: gcc -g -c shuffle.c Game.cgcc -g -o game game.o shuffle.o This puts the hook in executable, allowing GDB and KDBG to point out the operation. Debugging is a very important technology, it is worth speaking how to use how to use it. The debugger helps programmers is that it sets "breakpoints" in the source code. Now you can use the line of code to call the shuffle function to try to set the breakpoint. There will be a red small circle on the side of the line. Now when you press the F5 key, the program will stop executing there. Press F8 to jump into the shuffle function. Oh, we can now see the code in shuffle.c! We can control the program step by step and see what happened. If you pause the cursor on a local variable, you will see the contents of the variable. Great. This is much better than that printf statement, is it? Small junctions generally introduce the method of compiling and debug C procedures. We discussed the steps of the compiler, and to make the compiler do these jobs should be passed on which options for GCC. We briefly describe the problem of connecting the shared function library, and finally introduces the debugger. I really need to pay a lot of efforts, but I hope this article will let you start correctly. You can find more information in GCC, AS, and LD Man and Info Page. Write a code you can learn more. As an exercise, you can write a 21point game based on the card game of this article. At that time, you can learn how to use the debugger. It can be easier to use the KDBG using the GUI. If you only add a little bit every time, you can complete it soon. Remember, be sure to keep the program can always run! To write a complete game, you need the following: A card player's definition (ie, you can define DECK_T as Player_T). A function that gives a certain number of cards to the specified player. Remember to increase the number of "licensing" in cards, so that there are also those cards available. Also remember how many cards in the player. Some interactions with users and ask if the player has another card. A function that prints the card in player. Card is equal to value% 13 (number of 0 to 12), SUIT is equal to VALUE / 13 (the number of obtained 0 to 3). A function that determines the value in the player's hand. The Value of the ACE is zero and can be equal to 1 or 11. King's Value is 12 and can be equal to 10. Site Link GCC GCC GNU Compiler Collection GDB GNU Debugger Kdbg Kde's Gui Debugger Award Winning Compiler Hack Ken Thompson's Great Compiler HACK