C language - program compilation and linking

Translation environment and execution environment

The implementation of C language requires two environments:

  • A translation environment that converts source code into executable machine instructions .
  • The execution environment used to actually execute the code .

What is compiling and linking?

In the translation environment: source files are converted into object files through the compiler, and multiple object files are then formed into an executable program through the linker. (The translation process is shown in the figure)

 Subdivided, the compilation process is also divided into several stages.

  • 1. Preprocessing gcc -E test.c -o test.i
  • 2. Compile gcc -S test.c
  • 3. Assemble gcc -c test.c

Let's first take a look at what the execution environment does, and then look at the above process in detail.

  • 1. Loading the program into the memory is usually done by the operating system, and needs to be operated in an independent environment.
  • 2. Execution starts and the main function is called.
  • 3. Start executing the program code. At this point the program will use a runtime stack (stack) to store the function's local variables and return addresses. Programs can also use static memory. Variables stored in static memory retain their values ​​throughout the execution of the program.
  • 4. Terminate the program. Terminate the main function normally; it may also terminate unexpectedly

preprocessing symbols

__FILE__ //The source file to be compiled
__LINE__ //The current line number of the
file __DATE__ //The date the
file was compiled __TIME__ //The time the file was compiled
__STDC__ //If the compiler follows ANSI C, its value is 1, otherwise undefined

#define

define identifier

#define MAX 1000
#define reg register //Create a short name for the keyword register
#define do_forever for(;;) //Replace an implementation with a more vivid notation
#define CASE break;case //in Automatically write break when writing a case statement

define macro

Substituting parameters into text, this implementation is called defining a macro.

#define SQUARE( x ) x * x

However, there is a problem with this macro.

Question 1

int a = 5;
printf("%d\n" ,SQUARE( a + 1) );

The value we want to achieve is 36, but the actual output is 11, why?

 printf ("%d\n",a + 1 * a + 1 );

The actual replacement is 5+1*5+1, which is 11.

If you want to solve the above problem, put parentheses.

#define SQUARE(x) (x) * (x)

But an interesting new question arises below

Question 2

#define DOUBLE(x) (x) + (x)

int a = 5;
printf("%d\n" ,10 * DOUBLE(a));

We were expecting to print 100, but it actually outputs 55.

printf ("%d\n",10 * (5) + (5));

How to solve this? Add another parenthesis (both questions are essentially to solve the problem of priority)

#define DOUBLE( x) ( ( x ) + ( x ) )

When strings are used as macro parameters, we can put strings in strings.

 

The role of ##

## can combine the symbols around it into one symbol.

#define ADD_TO_SUM(num, value)
sum##num += value;
...
ADD_TO_SUM(5, 10);//The function is: add 10 to sum5.

#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
...
x = 5;
y = 8;
z = MAX(x++, y++);
printf("x= %dy=%dz=%d\n", x, y, z);//What is the output result?

 Because in practice z = ( (x++) > (y++) ? (x++) : (y++));

x++ once, y++ twice, and assign the value after the first ++ to z.

macros and functions

Macros are often used to perform simple operations. such as comparing the size

#define MAX(a, b) ( (a) > (b) ? (a) : (b) )

So why not use functions?

  • 1. The code for calling and returning from the function may take more time than actually doing this small computational work . So macros outperform functions in terms of program size and speed.
  • 2. More importantly, the parameters of the function must be declared as a specific type. So functions can only be used on expressions of the appropriate type. Conversely, how can this macro be applied to integers, long integers, floating point types, etc. that can be used for > to compare types. Macros are type-independent .

Are there any drawbacks to macros?

  • 1. Every time a macro is used, a copy of the macro definition code will be inserted into the program. Unless the macro is relatively short, it can significantly increase the length of the program.
  • 2. Macros cannot be debugged.
  • 3. Macros are not rigorous enough because they are type-independent.
  • 4. Macros may cause problems with operator precedence, making procedures prone to errors.

We put the two together into one graph.

 

#undef

 This directive is used to remove a macro definition

#undef NAME
//If an existing name needs to be redefined, its old name needs to be removed first.

start compilation

Many C compilers provide the ability to define symbols on the command line. Used to start the compilation process. For example, this feature is useful when we want to compile different versions of a program based on the same source file.

#include <stdio.h>
int main()
{
  int array [ARRAY_SIZE];
  int i = 0;
  for(i = 0; i< ARRAY_SIZE; i ++)
  {
    array[i] = i;
  }
  for(i = 0; i< ARRAY_SIZE; i ++)
  {
    printf("%d " ,array[i]);
  }
  printf("\n" );
  return 0;
}

gcc -D ARRAY_SIZE=10 programe.c

file contains

  • local files

#include "filename"

  • library file contains

#include <filename.h>

Guess you like

Origin blog.csdn.net/qq_59392324/article/details/122143879