热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【转】C宏

http:www.cs.yale.eduhomesaspnespinewikiC%282f%29Macros.htmlSeeKernighanRitchieAppendixA12.

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

 

Toggle line numbers
   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.

 

Toggle line numbers
   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

 

Toggle line numbers
   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.

 

Toggle line numbers
   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:

Toggle line numbers
   1 #include 
   2 
   3 #define Warning(...) fprintf(stderr, __VA_ARGS__)
   4 
   5 int
   6 main(int argc, char **argv)
   7 {
   8     Warning("%s: this program contains no useful code\n", argv[0]);
   9     
  10     return 1;
  11 }

It is possible to mix regular arguments with ..., as long as ... comes last:

Toggle line numbers
   1 #define Useless(format, ...) printf(format, __VA_ARGS__)
   2 

 

2. Multiple macros

One macro can expand to another; for example, after defining

 

Toggle line numbers
   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.

 

Toggle line numbers
   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

 

Toggle line numbers
   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

 

Toggle line numbers
   1     for(i = 0; i <n; i++) ...

all the time. In principle, you can write a macro

 

Toggle line numbers
   1 #define UpTo(i, n) for((i) = 0; (i) <(n); (i)++)
   2 

and then write

 

Toggle line numbers
   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:

 

Toggle line numbers
   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

 

Toggle line numbers
   1 #define HiHi() do { puts("hi"); puts("hi"); } while(0)
   2 

This can safely be used in place of single statements, like this:

 

Toggle line numbers
   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:

 

Toggle line numbers
   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

 

Toggle line numbers
   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

 

Toggle line numbers
   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:

 

Toggle line numbers
   1 #include 
   2 
   3 #define PrintExpr(x) (printf("%s = %d\n", #x, (x)))
   4 
   5 int
   6 main(int argc, char **argv)
   7 {
   8     PrintExpr(2+2);
   9     return 0;
  10 }

printExpr.c

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 <:

 

Toggle line numbers
   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 
   8     else if(bb 
   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

 

Toggle line numbers
   1 #include 
   2 
   3 /* note: must appear outside of any function, and has no trailing semicolon */
   4 DeclareSort(int, int)
   5 
   6 int
   7 main(int argc, char **argv)
   8 {
   9     int *a;
  10     int n;
  11 
  12     ...
  13 
  14     int_sort(a, n);
  15 
  16     ...
  17 }

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

 

Toggle line numbers
   1 #define DefinePlus1(x, y)  #define x ((y)+1)
   2 

or

 

Toggle line numbers
   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 宏


推荐阅读
  • 猫猫分享,必须精品原文地址:http:blog.csdn.netu013357243articledetails44571163素材地址:http:download.csdn.n ... [详细]
  • spotify engineering culture part 1
    原文,因为原视频说的太快太长,又没有字幕,于是借助youtube,把原文听&打出来了。中文版日后有时间再翻译。oneofthebigsucceessfactorshereatSpo ... [详细]
  • 以SOA服务为导向的信息系统构建是通过有计划地构建信息系统时,一种简单而有柔性的方法,就是组件化与服务导向架构。过去的信息系统,是在使用者需要新功能时才开发的,也就是响应不同时 ... [详细]
  • 接口测试的方式有很多,比如可以用工具(jmeter,postman)之类,也可以自己写代码进行接口测试,工具的使用相对来说都比较简单,重点是要搞清楚项目接口的协议是什么,然后有针对 ... [详细]
  • 作业迁移
    背景:数据库服务器更换,1、数据库迁移(BACKUPRESTORE);2、数据库登录名用户迁移(注意孤立用户);3、作业迁移数据库迁移,备份数据库、拷贝备份文件到新服务器,还原数据 ... [详细]
  • Illustrator绘制逼真的愤怒的小鸟实例教程
    Illustrator教程: ... [详细]
  • 抓取百万知乎用户设计之实体设计
    一.实体的关系实体是根据返回的Json数据来设计的教育经历方面用户可以有很多教育经理,USER和education是一对多的关系,一个education对应一个education一 ... [详细]
  • iOS之富文本
    之前做项目时遇到一个问题:使用UITextView显示一段电影的简介,由于字数比较多,所以字体设置的很小,行间距和段间距也很小,一大段文字挤在一起看起来很别扭,想要把行间距调大,结 ... [详细]
  • Xib九宫格应用管理使用xib封装一个自定义view的步骤1新建一个继承UIView的自定义view,假设类名叫做(AppView)2新建一个AppView.xib文件来描述 ... [详细]
  • 【自制小工具】代码生成器
    【自制小工具】代码生成器陆陆续续接触过好几款代码生成工具,发现确实好用,但都会有那么点不完善的地方,所以索性就自己做一个吧。界面非常简单,反正是自己用的,简单点用起来也方便上图:左 ... [详细]
  • kepserver中文手册,kepserver使用教程,kepserver设置
    下面介绍一下KepServer模拟器的使用,以下示例使用服务器随附的Simulator驱动程序来演示创建、配置和运行项目的过程。Simulator驱动程序是基于内存的驱动程序,能为 ... [详细]
  • 看这里,教你如何快速将pdf文件翻译成中文
    因为网上下载的PDF资料,往往掺杂着一些英文,所以中英文翻译是一件很平常的事,毕竟不是每个人的英文都那么好,轻轻松松的就能够看完一篇英文的文件,那么,我们就要寻找翻译工具来帮助我们 ... [详细]
  • 简单动态字符串redis里面很多地方都用到了字符串,我们知道redis是一个键值对存储的非关系型数据库,那么所有的key都是用字符串存储的,还有字符串类型,这些都是用字符串存储的 ... [详细]
  • 例子如Table表有性别字段,1代表男2代表女、3代表中性、还有没填就代表未说明selectid,decode(sex,'1','男', ... [详细]
  • C#的Type对象的简单应用
    通过Type对象可以获取类中所有的公有成员直接贴代码:classMyClass{privatestringname;privateintid;publicstringcity;pu ... [详细]
author-avatar
手机用户2602914827
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有