This is the 25th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

Program environment and preprocessing

The translation environment and execution environment of the program

In either implementation of ANSI C, there are two different environments

The first is a translation environment in which source code is converted into executable machine instructions

The second is the execution environment, which is used to actually execute the code

image-20210929062446170


Detailed compilation + link

Compile environment

image-20210929063247796


Each source file that makes up a program is converted into object code separately through the compilation process. Each object file is bundled together by the linker to form a single and complete executable program. The linker also introduces any functions from the standard C library that are used by the program, and it can search the programmer’s individual libraries to link the functions he or she needs into the program.

image-20210929063311384


image-20210929081838170


Pre-processing detail

Predefined symbol

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

These predefined symbols are built into the language

image-20211009050748724


image-20211009051336290


But GCC is supported. GCC supports C very well

#define

There are two things you can do with #define in C

#define a symbol

Syntax: #define name stuff

image-20211009052438743


#define MAX 1000
#define reg register      Create a short name for the register keyword
#define do_forever for(;;)   // Replace an implementation with a more graphic notation
#defineCASE break; case// Write "break" automatically when writing case statements.
// If you define stuff to be too long, you can write it in several lines, with a backslash followed by each line except the last.
#define DEBUG_PRINT printf("file:%s\tline:%d\t \ date:%s\ttime:%s\n" ,\
             __FILE__,__LINE__ ,    \
             __DATE__,__TIME__ )
Copy the code
image-20211009053424387


Pay attention to

When you define an identifier, do you want to add;

#define MAX 1000;
#define MAX 1000
Copy the code
image-20211009055130245


# define macros defined

image-20211009063939832


The #define mechanism includes a provision that allows parameters to be replaced into text. This implementation is often referred to as macro or define macro.

image-20211009061225500


What if I macro without parentheses

image-20211009062353419


Is that all right? So let’s just use your parentheses and see what’s missing

image-20211009063624841


This proves that preprocessing (compilation) is just text manipulation

Pay attention to

The opening parenthesis of the argument list must be next to name. If there is any white space between the two, the parameter list is interpreted as part of Stuff.

image-20211009064654448


The difference between define and typedef

One is substitution and the other is redefinition

image-20211009071624043


There is a question

image-20211009072823622


#define replace rule

There are several steps involved in extending #define definition symbols and macros in a program.

  1. When the macro is called, the parameters are first checked to see if they contain any symbols defined by #define. If so, they are replaced first.
  2. The replacement text is then inserted into the program where the original text was. For macros, parameter names are replaced by their values.
  3. Finally, the result file is scanned again to see if it contains any symbols defined by #define. If so, repeat the process.

Pay attention to

  1. Other #define variables can appear in macro parameters and #define definitions. But for macros, there is no recursion.
  2. When the preprocessor searches for symbols defined by #define,The contents of string constants are not searched.
image-20211009081444979


# and # #

How do I insert arguments into a string?

Use # to convert a macro argument to the corresponding string.

image-20211009103630360


Use # #

## combines the symbols on both sides of it into a symbol. It allows macro definitions to create identifiers from separate text fragments.

image-20211009104721452


Macro parameters with side effects

When a macro parameter appears more than once in the macro definition, if the parameter has side effects, you may be in danger of using the macro, leading to unpredictable consequences. A side effect is a permanent effect that occurs when an expression is evaluated.

x+1;// No side effects
x++;// With side effects
Copy the code
image-20211009110209148


image-20211009113746199


Macros versus functions

Macros are often used to perform simple operations. Like finding the larger of two numbers.

#defineMAX(a, b) ((a)>(b)? (a):(b))
Copy the code

So why not use a function to do that?

There are two reasons:
  1. The code used to call and return from the function may take more time than actually performing this little computational work.Macros are therefore superior to functions in terms of program size and speed.
  2. More importantly, function parameters must be declared of a specific type. So functions can only be used on expressions of appropriate type. Conversely, how can this macro be applied to integers, long integers, floating point types, etc., which can be compared with >?Macros are type independent.
Macros also have some disadvantages compared to functions:
  1. Each time a macro is used, a copy of the code defined by the macro is inserted into the program. Unless macros are shorter, it is possible to increase the length of your program substantially.
  2. Macros can’t be debugged.(Since we debug at run time, macros are replaced at compile time)
  3. Macros are not rigorous because they are type independent.
  4. Macros can introduce operator priority issues, making procedures prone to errors.

Macros can sometimes do things that functions can’t. For example, macro arguments can be typed, but functions cannot.

image-20211009145318151


A comparison of macros and functions

attribute # define macros defined function
The length of the code Macro code is inserted into the program each time it is used. With the exception of very small macros, the length of a program can grow substantially Function code only appears in one place; Every time you use this function, the same code in that place is called
Execution speed faster There is the overhead of calling and returning functions, so it is relatively slow
Operator priority Macro arguments are evaluated in the context of all surrounding expressions, and the precedence of the adjacent operators can have unpredictable consequences unless parentheses are used, so it is recommended that macros be written with parentheses. A function parameter is evaluated only once when the function is called, and its resulting value is passed to the function. The evaluation of the expression is more predictable.
Parameters with side effects Arguments can be replaced in multiple places in the macro, so parameter evaluations with side effects can produce unexpected results. Function parameters are evaluated only once during parameter passing, making the result more manageable.
The parameter types Macro parameters are type independent and can be used with any parameter type as long as the operation on the parameter is legal. The parameters of a function are type dependent, and if the parameters are of different types, you need different functions, even if they perform different tasks.
debugging Macros are not easy to debug Functions can be debugged statement by statement
recursive Macros are not recursive Functions can be recursive

Naming conventions

In general, function macros are syntactically similar. So language alone doesn’t help us distinguish between the two. So one of the things that we usually do is: capitalize all macros and don’t capitalize all functions

#undef

This directive is used to remove a macro definition

image-20211009155513895


Command line definition (VS is not supported, Linux is not available on this computer)

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 compiling different versions of a program from the same source file. (Suppose a program declares an array of some length. If the machine has limited memory, we need a small array, but if another machine has upper case, we need an array that can be capitalized.)

Conditional compilation

Code that meets the criteria is compiled; code that does not meet the criteria is not compiled

Such as:

Debug code, delete unfortunately, retain and hinder, so we can optionally compile.

image-20211009161934319


Common conditional compilation instructions

#if constant expression

#ifConstant expression
/ /...
#endif
Copy the code
image-20211009163553953


Pay attention to

It has to be a constant expression, not a variable

image-20211009164717300


Think about it for a moment: these variables are created at run time, but when is #if handled, during precompilation, before the local variable is created

Constant expressions are evaluated by the preprocessor.

// Constant expressions are evaluated by the preprocessor.
#define __DEBUG__ 1
#if __DEBUG__
/ /..
#endif
Copy the code
image-20211009164024619


Conditional compilation of multiple branches

#ifConstant expression
/ /...
#elifConstant expression
/ /...
#else
/ /...
#endif
Copy the code
image-20211009165834094


Determine if it is defined

#if defined(symbol)
#ifdef symbol
#if! defined(symbol)
#ifndef symbol
Copy the code
image-20211009171023343


Nested instruction

#if defined(OS_UNIX)
#ifdef OPTION1
unix_version_option1();
#endif
#ifdef OPTION2
unix_version_option2();
#endif
#elif defined(OS_MSDOS)
#ifdef OPTION2
msdos_version_option2();
#endif
#endif
Copy the code

File contains

We already know that the #include directive can cause another file to be compiled. Just as it actually appears in the #include directive. The way this substitution works is simple: the preprocessor first deletes the instruction and replaces it with something that contains the file. If such a source file is included 10 times, it is actually compiled 10 times.

How header files are included

Local files contain

#include "filename"
Copy the code

Search strategy: First look in the directory where the source file is located. If the header file is not found, the compiler looks for the header file in the standard location just as it looks for library function headers. If it cannot be found, it prompts a compilation error.

The library file contains

#include <filename.h>
Copy the code

To find the header file, go directly to the standard path. If it cannot be found, it will prompt a compilation error. Is it fair to say that library files can also be included in the form of “”? The answer is yes, it can. But this is less efficient, and of course it is not easy to distinguish between library files and local files.

Nested files contain

See my microcontroller that partial blog should be a bit more detailed