0%

C语言宏的一些说明 C macro

本文例子大多出自GCC的文档 GCC Macro Doc

Object-like Macros

Object-like marco 只会在使用时才会完全展开。

#define TABLESIZE BUFSIZE
#define BUFSIZE 1024
TABLESIZE
  ==> BUFSIZE
  ==> 1024

##Function-like Macros

function-like macro 只会在后面有 () 才会展开。

1
2
3
4
extern void foo(void);
#define foo() /* optimized inline version */
foo();
funcptr = foo;

注意如果定义了宏 foo(), 而又想定义foo函数,可以采用下面的做法。

1
2
3
4
5
#define foo() //inline function here
void (foo)()
{

}

加上()后就不会展开为宏了,在一些库中采用的就是这种方式。

注意在定义function-like macro时, 宏的名字和()中间不能有空格,否则会被展开为下面这种形式。

#define foo ()    c_init()
foo()
     ==> () c_init()()

如果这样定义宏, 会传递2个参数 array[x = yx + 1] 给宏,注意这个表达式中间有逗号。

macro (array[x = y, x + 1])

如果想用 array[x = y, x + 1] 作为参数,可以这样写 array[(x = y, x + 1)]

All arguments to a macro are completely macro-expanded before they are substituted into the macro body

可以传递空的参数给宏,但是必须要有逗号。

#define min(a,b) ((a) < (b) ? (a) : (b))
min(, b)        ==> ((   ) < (b) ? (   ) : (b))
min(a, )        ==> ((a  ) < ( ) ? (a  ) : ( ))
min(,)          ==> ((   ) < ( ) ? (   ) : ( ))
min((,),)       ==> (((,)) < ( ) ? ((,)) : ( ))

min()      error--> macro "min" requires 2 arguments, but only 1 given
min(,,)    error--> macro "min" passed 3 arguments, but takes just 2

宏的参数如果是在字符串中,则不会被替换。

#define foo(x) x, "x"
foo(bar)        ==> bar, "x"

字符串化(stringification)

用#可以将参数字符串化,
可以看到参数 x == 0 没有被展开, 而是变成 “x == 0”

1
2
3
4
5
6
7
#define WARN_IF(EXP) \
do { if (EXP) \
fprintf (stderr, "Warning: " #EXP "\n"); } \
while (0)
WARN_IF (x == 0);
==> do { if (x == 0)
fprintf (stderr, "Warning: " "x == 0" "\n"); } while (0);

如果希望EXP被展开,需要用2层的宏, 可以看到在很多地方使用这个技巧。

#define xstr(s) str(s)
#define str(s) #s
#define foo 4
str (foo)
     ==> "foo"
xstr (foo)
     ==> xstr (4)
     ==> str (4)
     ==> "4"

这里s在xstr中被展开, 这样在str中就是已展开的s。

Token pasting is most useful when one or both of the tokens comes from a macro argument. If either of the tokens next to an ‘##’ is a parameter name, it is replaced by its actual argument before ‘##’ executes. As with stringification, the actual argument is not macro-expanded first. If the argument is empty, that ‘##’ has no effect.

#define eprintf(…) fprintf (stderr, VA_ARGS)
The variable argument is completely macro-expanded before it is inserted into the macro expansion, just like an ordinary argument. You may use the ‘#’ and ‘##’ operators to stringify the variable argument or to paste its leading or trailing token with another token. (But see below for an important special case for ‘##’.)

If your macro is complicated, you may want a more descriptive name for the variable argument than VA_ARGS. CPP permits this, as an extension. You may write an argument name immediately before the ‘…’; that name is used for the variable argument. The eprintf macro above could be written
#define eprintf(args…) fprintf (stderr, args)

using this extension. You cannot use VA_ARGS and this extension in the same macro.

GNU CPP has a pair of extensions which deal with this problem. First, you are allowed to leave the variable argument out entirely:
eprintf (“success!\n”)
==> fprintf(stderr, “success!\n”, );

Second, the ‘##’ token paste operator has a special meaning when placed between a comma and a variable argument. If you write
#define eprintf(format, …) fprintf (stderr, format, ##VA_ARGS)

and the variable argument is left out when the eprintf macro is used, then the comma before the ‘##’ will be deleted. This does not happen if you pass an empty argument, nor does it happen if the token preceding ‘##’ is anything other than a comma.
eprintf (“success!\n”)
==> fprintf(stderr, “success!\n”);

revious versions of CPP implemented the comma-deletion extension much more generally. We have restricted it in this release to minimize the differences from C99. To get the same effect with both this and previous versions of GCC, the token preceding the special ‘##’ must be a comma, and there must be white space between that comma and whatever comes immediately before it:
#define eprintf(format, args…) fprintf (stderr, format , ##args)

However, if an identifier which is currently a macro is redefined, then the new definition must be effectively the same as the old one. Two macro definitions are effectively the same if:

* Both are the same type of macro (object- or function-like).
* All the tokens of the replacement list are the same.
* If there are any parameters, they are the same.
* Whitespace appears in the same places in both. It need not be exactly the same amount of whitespace, though. Remember that comments count as whitespace.

The C language offers no standard way to do this, but it can be done with GNU extensions as follows:
#define min(X, Y)
({ typeof (X) x_ = (X);
typeof (Y) y_ = (Y);
(x_ < y_) ? x_ : y_; })

The ‘({ … })’ notation produces a compound statement that acts as an expression. Its value is the value of its last statement. This permits us to define local variables and assign each argument to one. The local variables have underscores after their names to reduce the risk of conflict with an identifier of wider scope (it is impossible to avoid this entirely). Now each argument is evaluated exactly once.

If a macro x expands to use a macro y, and the expansion of y refers to the macro x, that is an indirect self-reference of x. x is not expanded in this case either. Thus, if we have
#define x (4 + y)
#define y (2 * x)

then x and y expand as follows:
x ==> (4 + y)
==> (4 + (2 * x))

y    ==> (2 * x)
     ==> (2 * (4 + y))

Each macro is expanded when it appears in the definition of the other macro, but not when it indirectly appears in its own definition.

Argument Prescan
Macro arguments are completely macro-expanded before they are substituted into a macro body, unless they are stringified or pasted with other tokens. After substitution, the entire macro body, including the substituted arguments, is scanned again for macros to be expanded. The result is that the arguments are scanned twice to expand macro calls in them.

#define AFTERX(x) X_ ## x
#define XAFTERX(x) AFTERX(x)
#define TABLESIZE 1024
#define BUFSIZE TABLESIZE

then AFTERX(BUFSIZE) expands to X_BUFSIZE, and XAFTERX(BUFSIZE) expands to X_1024. (Not to X_TABLESIZE. Prescan always does a complete expansion.)