c语言宏定义详解

所需积分/C币:10 2018-04-10 12:37:10 493KB PDF
收藏 收藏
举报

写好 C 语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方 便性 等等。下面列举一些成熟软件中常用得宏定义。。。。。。
(ray[0]=(va/256); Gray[1]=((val)&OXFF) 9,得到个变量的地址(word宽度) #define b ptr( var)((byte *)(void*)&(var)) #define w ptr( var)(word")(void *)&(var)) 10,得到一个字的高位和低位字节 #define word Lo(**x )(byte(word) x *)&255)) #define word Hi( * x((byte)((word)*)>>8)) 11,返回一个比X大的最接近的8的倍数 #define rnd(x) (X+7)/8)*8) 12,将一个字母转换为大写 # define UPCaSE(c)((c>='a&&(c)<='z")?(c)-0×20):(c) 13,判断字符是不是10进值的数字 #define dECChK(c(c>=0&&(c)<=9) 14,判断字符是不是16进值的数字 #define HeXchK(c(((c>=0&&(c<=9)\ (c)>='A'&&(c)<="F)l| (c)>='a&&(c)<=")) 15,防止溢出的一个方法 #define INC sat(val)(val =((val)+1 >(val))?(val)+1: val)) 16,返回数组元素的个数 #define arr siZe( a)( sizeof((a))/ sizeof((a[o]))) 17,返回一个无符号数n尾的值MoD_ BY POWER OF TWO(X, n)=X%(2^n) #define Mod BY PoWEr oF Two( val, mod by ((dword)(val)&(dword)((mod by)-1) 18,对于O空间映射在存储空间的结构,输入输出处理 #define inp(port) ((volatile byte *)(port)) #define inpw(port) (volatile word*)(port)) #define inpd 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) [2005-9-9添加] 19使用些宏跟踪调试 ANS|标准说明了五个预定义的宏名。它们是 LINE FILE DATE TIME STDC 如果编译不是标准的,则可能仅支持以上宏名中的几个,或根本不支持。记住编译稈序 也许还提供其它预定义的宏名。 LINE及FILE宏指令在有关#line的部分中已讨论,这里讨论其余的宏名。 DATE宏指令含有形式为月//年的串,表示源文件被翻译到代码时的日期。 源代码翻译到日标代码的时间作为串包含在_TIME_中。串形式为时:分:秒 如果实现是标准的,则宏STDC含有十进制常量1。如果它含有任何其它数,则实现是 非标准的。 可以定义宏,例如: 当定义了 DEBUG,输出数据信息和所在文件所在行 #ifdef debug #define deBugmsg(msg, date printf(msg);printf( %d%d%d,date line, FIle) #define dEBugmsg(msg, date #endif 20,宏定义防止使用是错 用小括号包含。 例如:# define add(a,b)(a+b) 用do{whle(O语句包含多语句防止错误 例如:# dine do(a,b)a+b; a++; 应用时:if(… Doa,b);产生错误 else C语言中如何使用宏 C(和C++)中的宏( Macro)属亍编译器预处理的范畴,属于编译期概念(而非运行期概念 下面对常遇到的宏的使用问题做了简单总结。 宏使用中的常见的基础问题 #符号和#符号的使用 符号的使用 宏的解释方法 我们能碰到的宏的使用 宏使用中的陷阱 常见的基础性问题 关于#和# 在C语言的宏中,#的功能是将其后面的宏参数进行字符串化操作( Stringfication),简单说 就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。比如下面代码中的宏 #define WARN IF(EXP) dof if (EXp) fprintfstderr, "Warning: #EXP n)) while(0) 那么实际使用中会出现下面所示的替换过程 WaRN IF (divider==0) 破替换为 do i if(divider==0 fprintf(stderr, "Warning""divider==0"n") y while(o) 这样每次dⅳ vider(除数)为0的时候便会在标准错误流上输出一个提示信息 而#被称为连接符( concatenator),用米将两个 Token连接为一个 Token。注意这里连接的 对象是 Token就行,而不一定是宏的变量。比如你要做一个菜单项命令名和函数指针组成的 结构体的数组,并且希望在函数名和菜单项命令名之间有直观的、名字上的关系。那么下面 的代码就非常实用 struct command char k name void(*function)(void) #define comMAnd(NAME)( NAME, NAME # command y /然后你就用一些预先定义好的命令来方便的初始化一个 command结构的数组了 struct command commands=i COMMAND(quit), COMMAND(help), COMMAND宏在这里充当一个代码生成器的作用,这样可以在一定程度上减少代码密度,间 接地也可以减少不留心所造成的错误。我们还可以n个#符号连接n+1个 Token,这个特性 也是#符号所不具备的。比如 #define linK mudtiplela, b, c, d)a####b####c####d typedef struct record type LInk_MULTIPlE(name, company, position, salary) ∥/这里这个语句将展开为: typedef struct record type name company position salary; 关于.的使用 在C宏中称为 Variadic macro,也就是变参宏。比如: #define myprintf(tempt,. fprintf( stderr, tempt, VA arGs ∥/或者 #define myprintf(tempt, args. printf(stderr, tempt, args) 第一个宏中由于没有对变参起名,我们用默认的宏WA_ARGS来梦代它。第二个宏中,我 们显式地命名变参为ags,那么我们在宏定义中就可以用args来代指变参了。同C语言的 std cal|一样,变参必须作为参数表的最有一项出现。当上面的宏中我们只能提供第一个参数 templ时,C标准要求我们必须写成: myprintf(tempt, ) 的形式。这时的替换过程为 myprintf("Error! \n") 替换为: fprintf(stderr, Error!\n,); 这是一个语法错误,不能止常编译。这个问题一般有两个解决方法。首先, GNU CPF提供的 解决方法允许上面的宏调用写成 myprintf(tempt 而它将会被通过替换变成: fprintf(stderr, Error!\n,); 很明显,这里仍然会产生编译错误(非木例的某些情况卜不会产生编译错误)。除了这种方 式外,c99和 GNU CPP都支持下面的宏定义方式: #define myprintf(tempt, fprintf(stderr, templ, # VAR ARGS 这时,#这个连接符号充当的作用就是当 VAR ARGS为空的时候,消除前面的那个逗号。 那么此时的翻译过程如下: 破转化为 fprintf( stderr, tempt); 这样如果 tempt合法,将不会产生编译错误。 宏是如何解释的 宏在日常编程中的常见使用 宏使用中的陷阱 这里列出了一些宏使用中容易出错的地方,以及合适的使用方式 错误的嵌套一 Misnesting 宏的定义不一定要有完整的、配对的括号,但是为了避兔出错并且提高可读性,最好避免这 样使用。 由操作符优先级引起的问题- Operator precedence problem 由于宏只是简单的替换,宏的参数如果是复合结构,那么通过替换之后可能由于各个参数之 间的操作符优先级高于单个参数内部各部分之间相互作用的操作符优先级,如果我们不用括 号保护各个宏参数,可能会产生预想不到的情形。比如: #define ceil div(x, y) (x+y-1)/y 那么 a =ceil div( b c, sizeof(int)); 将被转化为 a =(b&c + sizeof(int)-1)/ sizeof(int); ∥/由」+/-的优先级高」&的优先级,那么上面式子等同」: a=(b&(c+ sizeof(int)-1))/sizeof(int) 这显然不是调用者的初衷。为了避免这种情况发生,应当多写几个括号 define ceil div(x, y)(((x)+(y-1/y)) 消除多余的分号一 Semicolon Swallowing 通常情况下,为了使睬数模样的宏在表面上看起来像一个通常的C语言调用一样,通常情况 下我们在宏的后面加上一个分号,比如下面的带参宏 MY MACRO(x) 但是如果是下面的情况 #define MY Macro(x(\ if(condition() MY MACRO(a); else 这样会由于多出的那个分号产生编译错误。为了避免这种情况出现同时保持 MY MACRO(x); 的这种写法,我们需要把宏定义为这种形式: #define my macro(x do i 3 while(0 这样只要保证总是使用分号,就不会有任何问题。 Duplication of Side Effects 这里的 Side effect是指去在展开的时候对其参数可能进行多次 Evaluation(也就是取值),但 是如果这个宏参数是一个函数,那么就有可能被调用多次从而达到不一致的结果,甚至会发 生更严重的错误。比如 #define min (X,)((x> y?(y: X)) c= min(a, foo(b); 这时fo(数就被调用了两次。为了解决这个潜在的问题,我们应当这样写min(X,Y这个宏 #define min (X, y( typeof(x)x=(X;\ typeof ( y)y=(Y) (x<y_)?:y;) (…的作用是将内部的儿条语句中最后一条的值返回,它也允许在内部声明变量(因为它通 过人括号组成了一个局部 Scope) 充 、# define 命令# define定义了一个标识符及一个串。在源程序中每次遇到该标识符时,均以定义的串 代换它。ANS|标准将标识符定义为宏名,将替换过程称为宏 替换。命令的一般形式为: #define identifier string 注意 ?该语句没有分号。在标识符和串之间可以有任意个空格,串一旦开始,仅由一新行结束。 ?宏名定义后,即可成为其它宏名定义中的一部分。 ?宏替换仅仅是以文本串代替宏标识符,前提是宏标识符必须独立的识别出来,否刈不进行 替换。例如:# define xyz this is a test,使用宏 printf("XYz");∥/该段不打卬" this is a test"而打卬"XYz"。因为预编译器识 别出的是"XYz ?如果串长于一行,可以在该行末尾用一反斜杠\续行。 2、# error 处理器命令#eror强迫编详程序停止编详,主要用于程序调试。 、# i nclude 命令# i nclude使编译程序将另源文件嵌λ带有艹 i nclude的源文件,被读入的源文件必须 用双引号或尖括号括起来。例如 # i nclude" stdio. h"或者# i nclude 这两行代码均使用C编译程序读入并编译用于处理磁褴文件斥的了程序。 将文件嵌入# i nclude命令中的文件内是可行的,这种方式称为嵌套的坎入文件,嵌套层次 依赖」具体实现。 如果显式路径名为文件标识符的·部分,则仅在哪些了目录中搜索被嵌入文件。否则,如果 文件名用双引号括起来,则首先检索当前工作目求。如果未发现文件, 则在命令行中说明的所有目录中搜索。如果仍未发现文件,则搜索实现时定义的标准目录 如果没有显式路径名且文件名被尖括号括起来,则首先在编译命令行中的目录内检索 如果文件没找到,则检索标准目永,不检索当前工作目求。 4、条件编译命令 有儿个命令可对程序源代码的各部分有选择地进行编译,该过程称为条件编译。商业软件公 司广泛应用条件编译来提供和维护某一程序的许多顾客版本。 #f、#else,#elif及井 endif 拼的一般含义是如果#f后面的常量表达式为true,则编译它与井endf之问的代码,否则跳 过这些代码。命令#endf标识一个#f块的 结束。 #if constant-expression statement sequel fendi 跟在#后面的衣达式在编译吋求值,因此它必须仪含常量及已定义过的标识符,不可使用 变量。表达式不许含有操作符 sizeof( sizeof也是编译 时求值)。

...展开详情
试读 18P c语言宏定义详解
立即下载 低至0.43元/次 身份认证VIP会员低至7折
    抢沙发
    一个资源只可评论一次,评论内容不能少于5个字
    • GitHub

      绑定GitHub第三方账户获取
    关注 私信 TA的资源
    上传资源赚积分,得勋章
    最新推荐
    c语言宏定义详解 10积分/C币 立即下载
    1/18
    c语言宏定义详解第1页
    c语言宏定义详解第2页
    c语言宏定义详解第3页
    c语言宏定义详解第4页
    c语言宏定义详解第5页
    c语言宏定义详解第6页

    试读已结束,剩余12页未读...

    10积分/C币 立即下载 >