【转】C 宏
http://www.cs.yale.edu/homes/aspnes/pinewiki/C%282f%29Macros.html
See KernighanRitchie Appendix A12.3 for full details on macro expansion in ANSI C and http://gcc.gnu.org/onlinedocs/cpp/Macros.html for documentation on what gcc supports.
The short version: the command
1 #define FOO (12)
2
causes any occurrence of the word FOO in your source file to be replaced by (12) by the preprocessor. To count as a word, FOO can't be adjacent to other alphanumeric characters, so for example FOOD will not expand to (12)D.
1. Macros with arguments
To create a macro with arguments, put them in parentheses separated by commas after the macro name, e.g.
1 #define Square(x) ((x)*(x))
2
Now if you write Square(foo) it will expand as ((foo)*(foo)). Note the heavy use of parentheses inside the macro definition to avoid trouble with operator precedence; if instead we had written
1 #define BadSquare(x) x*x
2
then BadSquare(3+4) would give 3+4*3+4, which evaluates to 19, which is probably not what we intended.
1.1. Multiple arguments
You can have multiple arguments to a macro, e.g.
1 #define Average(x,y) (((x)+(y))/2.0)
2
The usual caveats about using lots of parentheses apply.
1.2. Perils of repeating arguments
Macros can have odd effects if their arguments perform side-effects. For example, Square(++x) expands to ((++x)*(++x)); if x starts out equal to 1, this expression may evaluate to any of 2, 6, or 9 depending on when the ++ operators are evaluated, and will definitely leave 3 in x instead of the 2 the programmer probably expects. For this reason it is generally best to avoid side-effects in macro arguments, and to mark macro names (e.g. by capitalization) to clearly distinguish them from function names, where this issue doesn't come up.
1.3. Variable-length argument lists
C99 added variadic macros that may have a variable number of arguments; these are mostly useful for dealing with variadic functions (like printf) that also take a variable number of arguments.
To define a variadic macro, define a macro with arguments where the last argument is three periods: ... . The macro __VA_ARGS__ then expands to whatever arguments matched this ellipsis in the macro call.
For example:
It is possible to mix regular arguments with ..., as long as ... comes last:
1 #define Useless(format, ...) printf(format, __VA_ARGS__)
2
2. Multiple macros
One macro can expand to another; for example, after defining
1 #define FOO BAR
2 #define BAR (12)
3
it will be the case that FOO will expand to BAR which will then expand to (12). For obvious reasons, it is a bad idea to have a macro expansion contain the original macro name.
3. Macro tricks
3.1. Multiple expressions in a macro
Use the comma operator, e.g.
1 #define NoisyInc(x) (puts("incrementing"), (x)++)
2
The comma operator evaluates both of its operands and returns the value of the one on the right-hand side.
You can also choose between alternatives using the ternary ?: operator, as in
1 #define Max(a,b) ((a) > (b) ? (a) : (b))
2
(but see the warning about repeated parameters above).
3.2. Non-syntactic macros
Suppose you get tired of writing
1 for(i = 0; i < n; i++) ...
all the time. In principle, you can write a macro
1 #define UpTo(i, n) for((i) = 0; (i) < (n); (i)++)
2
and then write
1 UpTo(i, 10) ...
in place of your former for loop headers. This is generally a good way to make your code completely unreadable. Such macros are called non-syntactic because they allow code that doesn't look like syntactically correct C.
Sometimes, however, it makes sense to use non-syntactic macros when you want something that writes to a variable without having to pass it to a function as a pointer. An example might be something like this malloc wrapper:
1 #define TestMalloc(x) ((x) = malloc(sizeof(*x)), assert(x))
2
(Strictly speaking, this is probably more of a "non-semantic" macro.)
Whether the confusion of having a non-syntactic macro is worth the gain in safety or code-writing speed is a judgment call that can only be made after long and painful experience. If in doubt, it's probably best not to do it.
3.3. Multiple statements in one macro
If you want to write a macro that looks like a function call but contains multiple statements, the correct way to do it is like
1 #define HiHi() do { puts("hi"); puts("hi"); } while(0)
2
This can safely be used in place of single statements, like this:
1 if(friendly)
2 HiHi();
3 else
4 snarl();
Note that no construct except do..while will work here; just using braces will cause trouble with the semicolon before the else, and no other compound statement besides do..while expects to be followed by a semicolon in this way.
3.4. String expansion
Let's rewrite NoisyInc to include the variable name:
1 #define BadNoisyInc2(x) (puts("Incrementing x"), x++)
2
Will this do what we want? No. The C preprocessor is smart enough not to expand macro parameters inside strings, so BadNoisyInc2(y) will expand to (puts("Incrementing x"), y++). Instead, we have to write
1 #define NoisyInc2(x) (puts("Incrementing " #x), x++)
2
Here #x expands to whatever the value of x is wrapped in double quotes. The resulting string constant is then concatenated with the adjacent string constant according to standard C string constant concatenation rules.
To concatenate things that aren't strings, use the ## operator, as in
1 #define FakeArray(n) fakeArrayVariableNumber ## n
2
This lets you write FakeArray(12) instead of fakeArrayVariableNumber12. Note that there is generally no good reason to ever do this.
Where this feature does become useful is if you want to be able to refer to part of the source code of your program. For example, here is short program that includes a macro that prints the source code and value of an expression:
When run, this program prints
2+2 = 4
Without using a macro, there is no way to capture the text string "2+2" so we can print it.
This sort of trickery is mostly used in debugging. The assert macro is a more sophisticated version, which uses the built-in macros __FILE__ (which expands to the current source file as a quoted string) and __LINE__ (which expands to the current source line number, not quoted) to not only print out an offending expression, but also the location of it in the source.
3.5. Big macros
Nothing restricts a macro expansion to a single line, although you must put a backslash at the end of each line to keep it going. Here is a macro that declares a specialized sorting routine for any type that supports <:
1 #define DeclareSort(prefix, type) \
2 static int \
3 _DeclareSort_ ## prefix ## _Compare(const void *a, const void *b) \
4 { \
5 const type *aa; const type *bb; \
6 aa = a; bb = b; \
7 if(aa < bb) return -1; \
8 else if(bb < aa) return 1; \
9 else return 0; \
10 } \
11 \
12 void \
13 prefix ## _sort(type *a, int n)\
14 { \
15 qsort(a, sizeof(type), n, _DeclareSort_ ## prefix ## _Compare); \
16 }
17
A typical use might be
Do this too much and you will end up reinventing C++ templates, which are a more or less equivalent mechanism for generating polymorphic code that improve on C macros like the one above by letting you omit the backslashes.
4. Debugging macro expansions
One problem with using a lot of macros is that you can end up with no idea what input is actually fed to the compiler after the preprocessor is done with it. You can tell gcc to tell you how everything expands using gcc -E source_file.c. If your source file contains any #include statements it is probably a good idea to send the output of gcc -E to a file so you can scroll down past the thousands of lines of text they may generate.
5. Can a macro call a preprocessor command?
E.g., can you write something like
1 #define DefinePlus1(x, y) #define x ((y)+1)
2
or
1 #define IncludeLib(x) #include "lib/" #x
2
The answer is no. C preprocessor commands are only recognized in unexpanded text. If you want self-modifying macros you will need to use a fancier macro processor like m4.
【转】C 宏的更多相关文章
- Visual Studio 宏的高级用法
因为自 Visual Studio 2012 开始,微软已经取消了对宏的支持,所以本篇文章所述内容只适用于 Visual Studio 2010 或更早期版本的 VS. 在上一篇中,我已经介绍了如何编 ...
- VC 中与字符串相关的宏 _T、TEXT,_TEXT、L 的作用
CSDN原博文:http://blog.csdn.net/houkai363/article/details/8134787 遇到了:不能将参数 1 从“const char [5]”转换为“LPCT ...
- 【转】linux内核中writesb(), writesw(), writesl() 宏函数
writesb(), writesw(), writesl() 宏函数 功能 : writesb() I/O 上写入 8 位数据流数据 (1字节) writesw() I/O 上写入 16 ...
- c++宏定义命令
在程序开始以#开头的命令,他们是预编译命令.有三类预编译命令:宏定义命令.文件包含命令.条件编译命令:今天聊聊宏定义: 宏定义命令将一个标识符定义为一个字符串,源程序中的该标识符均以指定的字符串来代替 ...
- dll导入导出宏定义,出现“不允许 dllimport 函数 的定义”的问题分析
建立dll项目后,在头文件中,定义API宏 #ifndef API_S_H #define API_S_H ...... #ifndef DLL_S_20160424 #define API _dec ...
- VC++/MFC 最常用宏和指令
1.#include指令 包含指定的文件,最基本的最熟悉的指令,编程中不得不用,包含库文件用双尖括号,包含自定义头文件用双引号. 2.#define指令 预定义,通常用它来定义常量(包括无参量与 ...
- [Sass]混合宏的参数
[Sass]混合宏的参数--传一个不带值的参数 Sass 的混合宏有一个强大的功能,可以传参,那么在 Sass 中传参主要有以下几种情形: A) 传一个不带值的参数 在混合宏中,可以传一个不带任何值的 ...
- [Sass]混合宏
[Sass]混合宏-声明混合宏 如果整个网站中有几处小样式类似,比如颜色,字体等,在 Sass 可以使用变量来统一处理,那么这种选择还是不错的.但当你的样式变得越来越复杂,需要重复使用大段的样式时,使 ...
- BOOST_AUTO宏
在boost中,有个非常不错的宏BOOST_AUTO(),它的作用是自动给var定义类型,适合function()函数返回的值的类型. int function() { ; } main() { BO ...
- C++预定义宏
C/C++宏体中出现的#,#@,##: - #的功能是将其后面的宏参数进行字符串化操作(stringfication),就是对它所引用的宏变量通过替换后在其左右各加上一个双引号 -##被称为连接符(c ...
随机推荐
- hdu5884 Sort(二分+k叉哈夫曼树)
题目链接:hdu5884 Sort 题意:n个有序序列的归并排序.每次可以选择不超过k个序列进行合并,合并代价为这些序列的长度和.总的合并代价不能超过T, 问k最小是多少. 题解:先二分k,然后在k给 ...
- for循环练习——7月23日
练习一:输入一个整数,求从1到这个数的累加和 //练习1:输入一个整数,计算从1加到这个数的结果 Console.Write("请输入一个正整数:"); int a = int.P ...
- 【转】Session ID/session token 及和cookie区别
Session + Cookie 知识收集! cookie机制采用的是在客户端保持状态的方案.它是在用户端的会话状态的存贮机制,他需要用户打开客户端的cookie支持.cookie的作用就是为了解决 ...
- spring mvc上传图片
1.需要commons-fileupload.jar commons-io.jar 2.需要在springmvc.xml中 配置存放静态资源的路径,对图片等静态资源放行 <mvc:resourc ...
- 使用MediaPlayer播放音频-----之二
MediaPlayer播放不同来源的音频文件: 一.播放应用的资源文件 1.调用MediaPlayer的create(Context context , int resid)方法加载指定资源文件. ...
- hdu 4612 Warm up
http://acm.hdu.edu.cn/showproblem.php?pid=4612 将原图进行缩点 变成一个树 树上每条边都是一个桥 然后加一条边要加在树的直径两端才最优 代码: #incl ...
- Dictionary解析json,里面的数组放进list,并绑定到DataGridView指定列
Dictionary解析json,1.根据json建立相应的实体类,json里面的数组形式放进list集合2.取list中的数据,将相应的数据绑定到DataGridView,如下:循环(动态添加一行数 ...
- Section 1.4 Packing Rectangles
本来是USACO Training的1.4.1的,但是介于今早过了食物链想起了这道题实在是太怨念了,翻出自己写的AC程序居然有5KB!! 思路很简单,枚举,而且就图中的六种情况.但是第六种变化状况太多 ...
- ctime、atime
Linux系统文件有三个主要的时间属性,分别是ctime(change time, 而不是create time), atime(access time), mtime(modify time).后来 ...
- 踏着前人的脚印学Hadoop——RPC源码
A simple RPC mechanism.A protocol is a Java interface. All parameters and return types must be one ...