How to Use Macros in C language, including Single and Double Well variable parameters

Source: Internet
Author: User

How to Use Macros in C language, including Single and Double Well variable parameters Favorites

Macros (macro) in C (and C ++) belong to the scope of compiler preprocessing, and belong to the concept of compilation period (rather than the concept of runtime ). The following briefly summarizes the frequently encountered macro usage problems.

About # And ##

In the macro of C language, # is used to stringize the macro parameters following it (stringfication ), simply put, a double quotation mark is added to the left and right sides of the macro variable referenced by the macro variable. 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 );

Replaced

Do {

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 connected object is a token, not necessarily 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 ##### d

Typedef struct _ record_type link_multiple (name, company, position, salary );

// Here the statement is expanded:

// 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 );

// 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 ();

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 ).

=

# Define display (name) printf ("" # name "")
Int main (){
Display (name );
}
The running result is name. Why not "# name?
---------------------------------------------------------------

# Here is what string means
Printf ("# name" ") is equivalent
Printf ("" name """)
---------------------------------------------------------------

The number-sign or "stringizing" Operator (#) converts macro parameters (after expansion) to string constants
---------------------------------------------------------------

Printf ("# name" ") <1>
Equivalent to printf ("" name "") <2>
In <2>, the second and second "intermediate time space cells are equivalent to (" null + name + null ')
---------------------------------------------------------------

# Connector and # Connector

# The Concatenation symbol is composed of two pound signs. Its function is to connect two substrings (tokens) in the macro definition with parameters to form a new substring. But it cannot be the first or last substring. The so-called token refers to the minimum syntax unit that the compiler can recognize. The specific definition has a detailed explanation in the compilation principle, but it does not matter if you do not know. At the same time, it is worth noting that the # operator replaces the passed parameters as strings. Let's take a look at how they work. This is an example on msdn.

Suppose the program has defined such a macro with parameters:
# Define Paster (n) printf ("token" # N "= % d", Token # N)

At the same time, an integer variable is defined:
Int token9 = 9;

Call this macro in the following way in the main program:
Paster (9 );

During compilation, the above sentence is extended:
Printf ("token" "9" "= % d", token9 );

Note that in this example, the "9" in Paster (9); is regarded as a string and connected with the "token", thus becoming the token9. # N is also replaced by "9.

As you can imagine, the result of running the program above is to print token9 = 9 on the screen.
---------------------------------------------------------------

# Define display (name) printf ("" # name "")
Int main (){
Display (name );
}
==========================================
The special feature is that it is a macro. Processing # in the macro is like ls!
After processing is an additional string!

But printf ("# name" "); it won't work!
---------------------------------------------------------------

# Define display (name) printf ("" # name "")

This definition is stringized name,
The result is actually printf ("name ")
(Remove the leading and trailing empty strings)

The output is name.

From another perspective,
# Is a connection symbol,
After calculation, it will not output...

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.