Tips for using macro definition in C Language

Source: Internet
Author: User

Write a good-looking macro definition in C language. Using macro definition can prevent errors, improve portability, readability, and convenience. The following lists some macro definitions commonly used in mature software ......
1. prevent a header file from being repeatedly contained
# Ifndef comdef_h
# Define comdef_h
// Header file content
# Endif
2. redefine some types to prevent the differences in the number of bytes of the types caused by different platforms and compilers, so as to facilitate migration.
Typedef unsigned char Boolean;/* Boolean value type .*/
Typedef unsigned long int uint32;/* unsigned 32 bit value */
Typedef unsigned short uint16;/* unsigned 16 bit value */
Typedef unsigned char uint8;/* unsigned 8 bit value */
Typedef signed long int int32;/* signed 32 bit value */
Typedef signed short int16;/* signed 16 bit value */
Typedef signed Char int8;/* signed 8 bit value */
// The following is not recommended
Typedef unsigned char byte;/* unsigned 8 bit value type .*/
Typedef unsigned short word;/* unsinged 16 bit value type .*/
Typedef unsigned long DWORD;/* unsigned 32 bit value type .*/
Typedef unsigned char uint1;/* unsigned 8 bit value type .*/
Typedef unsigned short uint2;/* unsigned 16 bit value type .*/
Typedef unsigned long uint4;/* unsigned 32 bit value type .*/
Typedef signed Char int1;/* signed 8 bit value type .*/
Typedef signed short int2;/* signed 16 bit value type. */typedef long int int4;/* signed 32 bit value type .*/
Typedef signed long sint31;/* signed 32 bit value */
Typedef signed short sint15;/* signed 16 bit value */
Typedef signed Char sint7;/* signed 8 bit value */
3. Get a byte or word on the specified address.
# Define mem_ B (x) (* (byte *) (x )))
# Define mem_w (x) (* (word *) (X )))
4. Calculate the maximum and minimum values.
# Define max (x, y) (x)> (y ))? (X): (y ))
# Define min (x, y) (x) <(y ))? (X): (y ))
5. Get the offset of a field in the struct (struct ).
# Define FPOs (type, field)
/* Lint-e545 */(DWORD) & (type *) 0)-> Field)/* lint + e545 */
6. Obtain the number of bytes occupied by the field in the struct.
# Define fsiz (type, field) sizeof (type *) 0)-> field)
7. convert two bytes into a word in LSB format
# Define flipw (Ray) (Word) (Ray) [0]) * 256) + (Ray) [1])
8. convert a word into two bytes in LSB format.
# Define flopw (Ray, Val)
(Ray) [0] = (VAL)/256 );
(Ray) [1] = (VAL) & 0xff)
9. Get the address of a variable (word width)
# Define B _ptr (VAR) (byte *) (void *) & (VAR ))
# Define w_ptr (VAR) (word *) (void *) & (VAR ))
10 to obtain the high and low bytes of a word.
# Define word_lo (***) (byte) (Word) (***) & 255 ))
# Define word_hi (***) (byte) (Word) (***)> 8 ))
11. Return a multiple of 8 nearest to X.
# Define rnd8 (x) + 7)/8) * 8)
12. convert a letter into uppercase letters.
# Define upcase (C) (c)> = 'A' & (c) <= 'Z ')? (C)-0x20): (c ))
13. determines whether the character is a decimal number.
# Define decchk (C) (c)> = '0' & (c) <= '9 ')
14. determines whether the character is a hexadecimal number.
# Define hexchk (C) (c)> = '0' & (c) <= '9 ')
(C)> = 'A' & (c) <= 'F ')
(C)> = 'A' & (c) <= 'F '))
15. A essentials to prevent overflow
# Define inc_sat (VAL) (val = (VAL) + 1> (VAL ))? (VAL) + 1: (VAL ))
16. returns the number of array elements.
# Define arr_size (A) (sizeof (a)/sizeof (A [0])
17. Return the value mod_by_power_of_two (x, n) = x % (2 ^ N) at the end of N)
# Define mod_by_power_of_two (Val, mod_by)
(DWORD) (VAL) & (DWORD) (mod_by)-1 ))
18. For the structure of Io space ing in the bucket, Input/Output Processing
# Define Indium (port) (* (volatile byte *) (port )))
# Define inpw (port) (* (volatile word *) (port )))
# Define inpdw (port) (* (volatile DWORD *) (port )))
# Define outp (port, Val) (* (volatile byte *) (port) = (byte) (VAL )))
# Define outpw (port, Val) (* (volatile word *) (port) = (Word) (VAL) # define outpdw (port, Val) (* (volatile DWORD *) (port) = (DWORD) (VAL )))
19. Use some macro tracking for debugging
The a n s I Standard specifies five predefined macro names. They are:
_ L I n e _
_ F I L E _
_ D a t e _
_ T I m e _
_ S t d c _
If compilation is not standard, Only one or more macro names are supported or not supported at all. Remember to compile the program
Other predefined macro names may also be provided.
The _ L I n e _ and _ f I l e _ macro commands have been discussed in the section about # l I n e. The remaining macro names are discussed here.
The _ d at E _ macro command contains a string in the form of month, day, or year, which indicates the date when the source file was translated to the code.
The time when the source code is translated to the target code is included in _ t I m e _ as a string. String format: minute: second.
If the implementation is standard, the macro _ s t d c _ contains a decimal constant 1. If it contains any other number, the implementation is non-standard.
You can define macros, for example:
When _ debug is defined, the output data and the row of the file
# Ifdef _ debug
# Define debugmsg (MSG, date) printf (MSG); printf ("% d", date, _ line _, _ file _)
# Else
# Define debugmsg (MSG, date)
# Endif
20. macro definition to prevent improper use
Enclosed in parentheses.
Example: # define add (a, B) (a + B)
Use the do {} while (0) statement to contain multiple statements to prevent incorrect
Example: # difne do (A, B) A + B;
A ++;
When using: If (....)
Do (a, B); // The result is incorrect.
Else
How to Use Macros in C Language
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 ). Next, we will give a basic summary of the frequently encountered macro Application Questions.
Common basic questions in macro operation
# Symbols and # use of symbols
...... Use of symbols
Essentials of macro Interpretation
Macro application we can encounter
Traps in macro operation
Common basic questions:
About # And ##
In the macro of C language, # is used to perform stringfication on macro parameters following it ), basically, 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 incorrect stream.
# Is called a concatenator to connect two tokens into a token. Note that the object connected here 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 connection 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 the 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;
About ...... Application
...... In the C macro, it is called variadic macro, that is, variable parameter 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. The C standard requires us to write it as: myprintf (templt ,);
. The replacement process is as follows:
Myprintf ("error! N ",);
Replace:
Fprintf (stderr, "error! N ",);
This is an incorrect syntax and cannot be compiled properly. There are generally two solutions to this question. First, the processing essentials provided by gnu cpp allow the above macro calls to be written:
Myprintf (templt );
It will be replaced:
Fprintf (stderr, "error! N ",);
Obviously, compilation is still incorrect here (not in this example, compilation is not correct 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 correct, the compilation will not be correct.
How macros are explained
Common Use of Macros in daily programming
Traps in macro operation
The following lists some locations that are prone to errors during macro operation and the appropriate use methods.
Incorrect nesting-misnesting
The macro definition does not have to have complete and paired parentheses, but it is best to prevent errors and improve readability.
Problems caused by operator priority-operator precedence Problem
Since macros are basically 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 prevent this from occurring, multiple parentheses should be written:
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
{......}
In this case, the compilation is incorrect due to the semicolon. To prevent this situation from keeping 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 doubt.
Duplication of side effects
The side effect here means that the macro may execute multiple evaluation (that is, the value) on its parameter during expansion, but 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 deal with this potential question, 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.