Advanced Application of C language macros

Source: Internet
Author: User
ArticleDirectory
    • Use...
    • Incorrect nesting-misnesting
    • Problems caused by operator priority-operator precedence Problem
    • Remove unnecessary semicolons-semicolon swallowing
    • Duplication of side effects

# And # In the macro of C language, # is used to stringfication the macro parameters following it. Simply put, it is referencedMacro variableAfter replacement, add a double quotation mark to each of the left and right sides. For exampleCodeMacro in:

# DefineWarn_if (exp)Do{If(Exp) fprintf (stderr,"Warning:"# Exp");}While(0)

 

In actual use, the following replacement process will appear:

Warn_if (divider =0); Is replacedDo{If(Divider =0) Fprintf (stderr,"Warning" "Divider = 0" "");}While(0);

 

In this way, when divider (divider) is 0, a prompt message will be output on the standard error stream.

# Is called a concatenator to connect two tokens into one. Note that the object connected here is a token, andNot necessarilyIs a macro variable. For example, you want to create an array composed of a menu item command name and a function pointer, and you want to have an intuitive and name relationship between the function name and the menu item command name. The following code is very practical:

 
StructCommand {Char*Name;Void(* Function )(Void);};# DefineCommand (name ){Name, name ##_ command}

// Then you can use some pre-defined commands to easily Initialize an array of command structures:

 
StructCommand commands [] = {command (quit), command (help ),...}

 

The command macro acts as a code generator here, which can reduce the code density to a certain extent and indirectly reduce errors caused by carelessness. We can also use N # symbols to connect n + 1 token. This feature is also not available for # symbols. For example:

# DefineLink_multiple (A, B, C, D) A ##### B #### C ##### dTypedefStruct_ Record_type link_multiple
(Name, company, position, salary );
//The statement is expanded as follows://Typedef struct _ record_type name_company_position_salary

 

Use...

... It is called variadic macro in macro C, that is, variable macro. For example:

 
# Define myprintf (templt,...) fprintf (stderr, templt ,__ va_args __)
// Or
# Define myprintf (templt, argS...) fprintf (stderr, templt, argS)

In the first macro, the default macro _ va_args _ is used instead of the variable parameter. In the second macro, we explicitly name the variable parameter as ARGs, so we can use ARGs to represent the variable parameter in the macro definition. Like stdcall in C, the variable parameter must appear at the most of the parameter table. In the macro above, we can only provide the first templt parameter. The C standard must be written as follows:

 
Myprintf (templt ,);

. The replacement process is as follows:

Myprintf ("error! ",);
Replace:
Fprintf (stderr, "error! ",);

This is a syntax error and cannot be compiled properly. There are two solutions to this problem. First, the solution provided by gnu cpp allows the preceding macro call to be written:

 
Myprintf (templt );

It will be replaced:

 
Fprintf (stderr, "error! ",);

Obviously, compilation errors will still be generated here (not in this example, compilation errors will not be generated in some cases ). In addition to this method, both c99 and gnu cpp support the following macro definition methods:

 
# Define myprintf (templt,...) fprintf (stderr, templt, ##__ var_args __)

In this case, the # connection symbol is used to remove the comma before when _ var_args _ is empty. The translation process is as follows:

 
Myprintf (templt );
Converted:
Fprintf (stderr, templt );

In this way, if the templt is valid, no compilation error will be generated.

Incorrect nesting-misnesting

The macro definition does not have to have complete and paired parentheses. However, to avoid errors and improve readability, it is best to avoid this.

Problems caused by operator priority-operator precedence Problem

Since macros are simply replaced, if macro parameters are in a composite structure, the priority of the operators between parameters may be higher than that of the operators that interact with each other within a single parameter, if we do not use parentheses to protect macro parameters, unexpected situations may occur. For example:

# Define ceil_div (x, y) (x + y-1)/y

So

 
A = ceil_div (B & C, sizeof (INT ));

Will be converted:

 
A = (B & C + sizeof (INT)-1)/sizeof (INT );
// Because the priority of +/-is higher than the priority of &, the preceding formula is equivalent:
A = (B & (C + sizeof (INT)-1)/sizeof (INT );

This is clearly not the original intention of the caller. To avoid this, you should write several parentheses:

 
# Define ceil_div (x, y) (x) + (y)-1)/(y ))
Remove unnecessary semicolons-semicolon swallowing

Generally, to make a macro look like a common C language call on the surface, we usually add a semicolon after the macro, such as the following macro with parameters:

 
My_macro (X );

But in the following case:

 
# Define my_macro (x ){
/* Line 1 */
/* Line 2 */
/* Line 3 */
}
//...
If (condition () my_macro (a); else {...}

This will cause a compilation error due to the semicolon that appears. To avoid this situation and maintain my_macro (x); at the same time, we need to define the macro as this form:

# Define my_macro (x) do {/* Line 1 * // * Line 2 * // * Line 3 */} while (0)

In this way, as long as the semicolon is always used, there will be no problems.

Duplication of side effects

Here, side effect indicates that the macro may perform multiple evaluation (that is, the value) on its parameter during expansion. However, if this macro parameter is a function, therefore, it may be called multiple times to achieve inconsistent results, or even cause more serious errors. For example:

 
# Define min (x, y) (x)> (y )? (Y): (x ))
//...
C = min (A, Foo (B ));

The Foo () function is called twice. To solve this potential problem, we should write the macro min (x, y) as follows:

 
# Define min (x, y) ({typeof (x) X _ = (x); typeof (y) Y _ = (y); (X _ <Y _)? X _: Y _;})

({...}) The function is to return the last value of several internal statements. It also allows variable declaration in the internal (because it forms a local scope through braces)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.