Some special usage of Macros in C Language

Source: Internet
Author: User

Reprinted
In C language, how to use macros (macro) in macro C (and C ++) belongs to the scope of compiler preprocessing and to the concept of compilation period (rather than runtime ). The following briefly summarizes the frequently encountered macro usage problems.

About # And ##

In the macro of C language, the # function is to stringize the macro parameters following it (stringfication). Simply put, it is referencedMacro variableAfter replacement, add a double quotation mark to each of the left and right sides. For example, the macro in the following code:

#define WARN_IF(EXP)    \    do{ if (EXP)    \            fprintf(stderr, "Warning: " #EXP "\n"); }   \    while(0)

In actual use, the following replacement process will appear:

Warn_if (divider = 0 );ReplacedDo {If (divider = 0) fprintf (stderr, "warning" "divider = 0" "\ n") ;}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:

Struct command {char * Name; void (* function) (void) ;};# define command (name) {Name, name ##_ command} // then you can use some pre-defined commands to easily Initialize an array of command structures: struct Command 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:

# Define link_multiple (A, B, C, D) A ##### B ##### C ##### dtypedef struct _ record_type link_multiple (name, company, position, salary); // The statement is expanded to: // 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 parameter templt, and the c Standard requires us to write:

myprintf(templt,);

. The replacement process is as follows:

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

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!\n",);

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. The following lists the error-prone areas in macro usage and the appropriate usage methods.

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); // Since the priority of +/-is higher than the priority of &, the formula above 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.