Summary of the usage of macro definitions

Overview

A macro definition is a code fragment with a given name. When we use this name, the preprocessor will automatically replace it with the content of the macro definition. There are two types of macro definitions, one is object-like macro definition, which is equivalent to a data object when used; the other is function-like, which is like calling a function when used.

The content of the macro definition can be arbitrary, even C keywords (unavailable content special case [preprocessing command]defined,[c++ named operators]and_eq,bitand,bitor,compl,not,not_eq,or,or_eq,xor, xor_eq)

Macro expansion will make the source program longer, but the macro expansion occurs during the compilation process and does not take up the running time, only the compilation time.

Because macro expansion occurs during the preprocessing stage, no memory will be allocated.
When the Macro Replacement Occurs

The process of compiling c source program:

    Pre-
    compile
    assembly
    link

The preprocessing produces the output of the compiler, and the functions are as follows. The
file contains

Expand the content contained in #include to the body of the file, that is, find the .h file, and expand it to the location of #include at the same time.
Conditional compilation

According to compilation commands such as #if and #ifdef, part of the source program file is included, partly excluded, and the excluded ones are generally converted to blank lines.
Macro expansion

Expand the call to the macro into the corresponding macro definition
object-like macro definition
form

    Normal form: #define <macro name> <string>

#define is followed by the name of the code segment defined by the macro, and then the token sequence represented by the macro name

    Generally speaking, we use object-like macro definitions to give a symbol instead of numeric constants

    例子: #define BUFFER_SIZE 1024

    The macro name here is BUFFER_SIZE, and the token sequence to be replaced is 1024. Then when you use BUFFER_SIZE, the preprocessor will expand it so that the compiler will treat it as 1024 when processing

    For example, the source code foo = (char*)malloc(BUFFER_SIZE), after being processed by the preprocessor, the compiler equates it to foo = (char*)malloc(1024).

usage

    Generally speaking, the macro name is written in all capital letters (conventional, easy to read)

    The #define command will stop at the end of the line. If you want to act on multiple lines at the same time, you need to add \ at the end, and pay attention not to add blanks such as spaces after \, just line breaks

    E.g

    #define NUMBERS 1, \
                    2, \
                    3
        1
        2
        3

    Equivalent to

    #define NUMBERS 1, 2, 3
        1

    There are almost no restrictions on the content of the string defined by the macro (you need to ensure the balance of the parentheses)

    Since the C preprocessor is sequential when processing the program, the macro definition starts from its defined position.

    Macro definitions can be nested definitions, which means that if another macro definition name is encountered during replacement, the replacement will continue

    In other words

    #define A B
    #define B 1
        1
        2

    In the preprocessing, A ⟶ BA\longrightarrow BA⟶B, and then continue to check whether BBB is a macro name, replace B ⟶ 1 B\longrightarrow1 B⟶1, and replace A with 1 after the final replacement. It should be noted that when nesting definitions, if a certain macro name that has been checked is encountered during recursive checking, it will not continue to expand, thus avoiding recursive calls.

doubt

An article I read thinks

#define A B
#define B 1

    1
    2

versus

#define B 1
#define A B

    1
    2

There will be differences, the difference is that in the latter definition method, A will always be equal to the current effective value of B.

The result of my experiment is that both can be equal to the current effective value of B. I don’t understand what the article means. The concept of
self-referential macros

A self-referencing macro means that the name of the macro appears in its own macro definition. For example #define foo(4 + foo)

The rule of self-referencing macros In order to avoid endless recursive calls, calls such as (4+(4+(4+(4+foo)))) are generated, and it is forbidden to replace a macro name that has appeared again, that is Say that the above definition will only produce 4+foo.

Indirect self-referencing macros such as

#define x (4 + y)
#define y (2 * x)

    1
    2

Also follow the above rules, do not replace a macro name that has already appeared.
usage

Usually self-referencing macros directly

#define EPERM EPERM

    1

Here EPERM is a defined quantity, so the code after #ifdef EPERM will run successfully.
function-like macro definition
concept
without parameters

Like #define <macro name>(<parameter list>) <macro body>

That is, a pair of parentheses must be immediately followed by the macro name.

When used, it must also be followed by a pair of parentheses, otherwise no replacement

In other words, after foo is preprocessed, it is still foo, and only foo() will be replaced with <macro body>

If there is a blank character (space, tab, etc.) between the macro name and the parentheses when defining it, such as #define test () my(), then what you define at this time is an object-like macro definition, for test It will be replaced with () my(), and test() will be replaced with () my()(). Note that it is not a function-like macro definition, and the parentheses after test() will not disappear.
With parameters

Those with parameters still have to follow the above rules, the difference is that the parameters are placed in parentheses immediately after the macro name, just like a real function.

For example #define <macro name>(<parameter list>) <macro body>

Note that the parameters in the parameter list must be valid c identifiers, separated by,
Usage

When you define a function-like macro definition such as #define min(X,Y) ((X) <(Y)? (X): (Y)), to call it, you only need to use the macro name followed by parameter list. Note that the number of parameters when you call should be exactly the same as the number of parameters in the macro definition.

For example, min(a,b) is equivalent to the use of ((a) <(b)? (A): (b)) such a ternary operator. The parameter list uses, as the delimiter, and () must appear in pairs. At the same time, **(,) in parentheses is not used as a separator**, that is to say, min((a,b)) actually you only pass A parameter (a, b), but there are no such requirements and rules for square brackets [] and curly brackets, they do not have to appear in pairs, and it does not affect the function as a separator, such as min([a,b]) Two parameters [a and b] are passed.

At the same time, the parameters defined by the function-like macro must have been completely replaced by the macro. That is to say, if you call min(min(a,b),c) and pass two parameters min(a,b),c, first Macro substitution for these two parameters, then min(a,b) will also become ((a) <(b)? (A): (b)), and then pass in this form.

During the parameter transfer process of the macro definition, whitespace is allowed to be the parameter passed, but no matter what kind of whitespace, it is considered as a pure whitespace during the transfer process, even if it turns out to be 5 spaces, it is only considered as a parameter. Such as calling min (, b) is passed two parameters and b, macro substitution result is (() <(b) ( ):? (B))
Notes

    In <macro body>, if you add "" to the parameter, the parameter will not be replaced

    E.g

    #define foo(x) x,"x"
        1

    The call is foo(bar), replaced with bar, "x", and the x in "x" is not treated as a parameter.

Special usage
stringification
concept

Use # to change the parameter x into the corresponding string

    Demo

    #define TOSTRING(X) #x, apply this macro definition, and the final replacement will be a string.

    For example, TOSTRING(x==0), the resulting replacement is "x==0"

Precautions

    It should be noted that for the #stringified parameters, there is no need to perform macro expansion and substitution, but directly substitute

    #define A B
    TOSTRING(A)
        1
        2

    The replacement produced here is "A", not "B", because stringification is a direct replacement.

    #Stringification is not simply adding "" on both sides of the original parameters, but turning the characters that need to be escaped into escape characters.

    For example, when the parameter is p = "foo\n"; the resulting string is "p = \"foo\\n\";|.

    If there are whitespace characters in it, the whitespace at the beginning and the end will be discarded when it is converted into a string, and the middle will become a space.

    In this way, the output string can be connected with the surrounding string to be called a long string

    For example: #define TOSTRING(X) "test" #X "temp", assuming the parameter is p = "foo\n", then the final string will be "testp = \"foo\\n\temp";|

Token concatenation
concept

Use ## to connect the two tokens together. The token here can be the content of the macro body or the parameter.

The usage method is as follows: A##B. If A and B are both the contents of the macro body, then the content after the connection must be a valid c content. For example, characters like x##+ are not allowed to exist, of course x##+5 Can exist.
Precautions

    The connection function of ## also takes precedence over macro expansion, that is, the ## operator is called first.
    A blank character of any length can be placed between ## and its operand, but the ## operator cannot be placed at either end of the macro body. Obviously there will be no operation if ## is connected with a blank character

Variable macro definition
concept

The function-like macro definition can also not fix the number of parameters, and replace all parameters with a special identifier.

例如#define eprintf(...) fprintf(stderr,__VA_ARGS__)

The inside... means that the parameters in eprintf are variable, all of which are used to replace __VA_ARGS__, and __VA_ARGS__ is a reserved keyword, do not use it in other places, it is specifically used to replace variable parameters.

So when eprintf("%s:%d",input_file,lineno) is used, it will be replaced by fprintf(stderr,"%s:%d",input_file,lineno).

It is also possible to add a custom name to the variable parameter. It is only allowed to write a custom name directly before..., for example #define eprintf(st...) fprintf(stderr,st), where st is Custom name.
Special usage

    Variable parameters and fixed parameters can exist at the same time, such as #define eprintf(format, ...) fprintf(stderr,format,__Va_ARGS__). Under the old compiler, at least two parameters must be provided, one for format and one for .... And the second parameter cannot be empty

    More content

Predefined macros

    There are some macro definitions defined in advance, which are all object-like macro definitions, which are divided into three categories, standard, common, and system-specific

    In C++, there are named operators (named operators)

standard predefined macro

The standard predefined macros are specified by the language standard and are available on all standard-compliant compilers. The names all begin with a double underscore
____FILE__

Current source file name, type: c style string array
__LINE_

The number of rows currently entered, type: int constant

#line lineNum, where lineNum is a non-negative decimal integer constant, specify the __LINE_ of the next line as lineNum

#line lineNum fileName, lineNum non-negative decimal integer constant, specify the next line __LINE__ as lineNum, fileName string constant. Change all the __FILE__ values ​​at the beginning of the next line to fileName, and the characters still need to be escaped
__DATE_

Date when the preprocessor was run, type: string constant

Contains 11 characters, example Feb 12 1996

If the date cannot be determined, a warning is issued, and __DATE_ becomes ??? ?? ????
__TIME_

Time when the preprocessor was running, type: string constant

Contains 8 characters, example: 23::50::01

It is also uncertain to issue a warning, and it becomes ??:??:??
__STDC__

If the compiler follows the ISO standard C, set to 1

If GNU CPP is not using the GCC compiler, it does not have to be true

-traditional-cpp option and __STDC__ are mutually exclusive, only one is used
__STDC_VERSION__

C standard version number, type: long

Format: yyyymmL, where yyyy is the year of the standard version and mm is the month

It is also mutually exclusive with -traditional-cpp, and will not be defined when compiling c++
__STDC_HOSTED

The target of the compiler is the hosted environment, set to 1

The hosted environment consists of the fully usable c standard library tool
__cplusplus

When using the C++ compiler, this macro is defined

Expanded to version number, also yyyymmL
__OBJC__

When using objective-c compiler, it is set to 1
__ASSEMBLER__

When preprocessing assembly language, set to 1
common predefined macro

    It is a GNU C extension. Available when using GNU C or GNU Fortran.

    Also start with a double underscore __

__COUNTER__

This macro expands to sequential integer values ​​starting from 0.

Together with the ## operator, this provides a convenient way to generate unique identifiers. Care must be taken to ensure that COUNTER is not expanded before including precompiled headers that use it. Otherwise, the precompiled header
__GFORTRAN__ will not be used

GNU Fortan compiler definition
__GNUC__
__GNUC_MINOR__
GNUC_PATCHLEVEL__

GNU compiler definition. They are the major version, minor version, and the level of the patch. Type: integer
__GNUG__

GNU C++ compiler definition

Equivalent to __GNUC__ && __cplusplus
__STRICT_ANSI__

Mainly used to instruct GNU libc header files to only use definitions found in standard C.
__BASE_FILE__

The name of the main input file, type: c string
__INCLUDE_LEVEL__

Contains the nesting depth of the file, type: decimal integer constant
__ELF__

Use ELF object format, define this macro
__VERSION__

The version of the compiler used, type: string constant

No specific format
system-specific predefined macros

Use cpp -dM to view the entire content.

It depends on the system and machine type being used.

    The C standard requires that all system-specific macros must be part of the reserved namespace. All names beginning with two underscores or underscores and capital letters are reserved for use by the compiler and libraries.

c++ named operators

There are 11 keywords in c++, which are operator substitutions of operators.

    and -> &&
    and_eq -> &=
    bitand -> &
    bitor -> |
    compl -> ~
    not -> !
    not_eq -> !=
    or -> ||
    or_eq -> |=
    xor -> ^
    xor_eq -> ^=

Cancel macro definition and redefine
undef cancel macro definition

To stop interrupting the use of a macro definition, you only need to add #undef in front of the macro definition name, and do not add parentheses in the function-like macro definition.

E.g

#define FOO 4
#undef Foo //Stop using FOO
#define FOO(X) X*X
#undef FOO //function-like macro definition is also canceled

    1
    2
    3
    4

redefine

    An identifier that has been #undef can be defined. At this time, it is equivalent to defining a brand new macro. The macro does not need to have any relationship with the original function of the identifier. You can define it at will

    Assuming that the redefined identifier is still a valid macro definition at this time, the new definition must have the same effect as the original one.

    The requirements for the same utility are as follows:
        the same type of macro definition (object-like or function-like)
        replaces the token in the list, the same
        parameter, the same
        blank character appears in the same position (the number is not important, the position is important), and the comment will be blank Replace

    Examples of different utility

    #define FOUR (2 + 2) //The original definition
    #define FOUR (2+2) //The blank character position is different
    #define FOUR (2 * 2) //token is different
    #define FOUR(score,and,seven,years ,ago) (2 + 2) //The parameter list is different
        1
        2
        3
        4

    If the redefined macro in this way is not similar before and after, then a warning will be generated, and then the macro definition will be replaced with the latter

Common usage of macro definitions to
prevent header files from being repeatedly included

#ifndef BODY_H //Ensure that the content of the header file will be expanded only if the header file is not included

#define BODY_H

//Header file content

#endif

    1
    2
    3
    4
    5
    6
    7

Get a byte or a word at the specified address

#define MEM_B(x) (*(byte*)(x)) //Get a byte at the address represented by x
#define MEM_W(x) (*(word*)(x)) //Get the value represented by x A word on the address

    1
    2

Get the offset of a field in the structure

#define OFFSET(type,field) (size_t)&((type*)0->field)

    1

Get the number of bytes occupied by a field in a structure

#define FSIZ(type,field) sizeof(((type*)0)->field)

    1

Get the address of a variable

#defien B_PTR(var) ((byte*)(void*)&(var)) //Get the byte width address
#define W_PTR(var) ((word*)(void*)&(var)) // Get the address of the word width

    1
    2

Convert a letter to uppercase

#define UPCASE(c) (((c) >= "a" && (c) <= "z") ? ((c) - 0x20) : (c) )

    1

Prevent overflow

#define INC_SAT(val) (val = ((val) +1 > (val)) ? (val) + 1 : (val))

    1

Returns the number of array elements

#define ARR_SIZE(a) (sizeof( (a)) / sizeof(a[0])))
————————————————
Copyright statement: This article is the CSDN blogger "leadingwerido" The original article of, follow the CC 4.0 BY-SA copyright agreement, please attach the original source link and this statement for reprinting.
Original link: https://blog.csdn.net/leadingfigure/article/details/105922622

Guess you like

Origin blog.csdn.net/daocaokafei/article/details/115265805