• 博客园logo
  • 会员
  • 周边
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

SOC/IP验证工程师

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

c语言中宏的用法汇总

1.用作符号常量/明示常量时
#define预处理指令和其他预处理指令一样,以#号作为一行的开始。指令可以出现在源文件的任何地方,其定义从出现的地方到该文件的末尾有效。
预处理器指令从#开始,到后面的第一个换行符为止。宏的名字中不允许有空格,而且必须遵循c变量的命名规则:只能使用字母/数字/下划线,而且首字符不能是数字。
注意,宏定义还可以包含其他宏(一些编译器不支持这种嵌套功能)。
例如:

#define TWO 2        //添加注释
#define FOUR TWO*TWO /*宏展开为2*2,由于编译器在编译期对所有常量表达式(只包含常量的表达式)求值,所以预处理器不会进行实际的乘法运算,预处理不做计算,不对表达 
                      式求值,它只进行替换。*/
#define OW "I am\
a student"           //反斜杠把该定义延续到下一行
#define HAL 'Z'      //定义一个字符常量
#define HAL "Z"      //定义一个字符串
printf("TWO: OW");

打印结果:TWO: OW
一般而言,预处理器发现程序中的宏后,会用宏等价的替换文本进行替换,如果替换的字符文本中还包含宏,则继续替换这些宏。唯一例外的是双引号中的宏。

#define LIMIT 20
const int LTM = 50;
static int data1[LIMIT];      //有效
static int data2[LTM];        //无效
const int LIM2 = 2 * LIMIT;  //有效
const int LIM2 = 3 * LTM;     //无效

c语言现在支持const关键字,用const可以创建在程序运行时不能改变的变量,宏常量也可用于指定标准数组的大小和const变量的初始值。
在c中,非自动数组的大小应该是整型常量表达式,这说明数组大小必须是整型常量的组合,枚举常量和sizeof表达式。不包括const声明值。但是有的实现可能接受其他形式的常量表达式,例如GCC4.7.3不允许data2的声明,但是Clang4.6允许。

2.在#define中使用参数
在#define中使用参数可以创建外形和作用与函数类似的类函数宏。类函数宏定义的圆括号可以有一个或多个参数。

#define SQUARE(X) X*X
#define PR(X) printf("The result is %d.\n", X)    /宏可以表示任何字符串,甚至可以表示整个c表达式/

int x = 5;
SQUARE(x);    //x*x=5*5=25
SQUARE(2);    //2*2=4
SQUARE(x+2);  //x+2*x+2=17 预期(x+2)(x+2) 
//以上用#define SQUARE(x) (x)*(x)
(100/SQUARE(2))  //100/2*2=100 预期100/(x+2)
//以上用#define SQUARE(x) (x*x)
SQUARE(++x)      //++x*++x=42  预期(x+1)*(x+1)
//综合以上可用#define SQUARE(x) ((x)*(x))一次性全部解决

3.用宏参数创建字符串:#运算符
C允许在字符串中包含宏参数。在类函数宏的替换体中,#号作为一个预处理运算符,可以把记号转换成字符串。如果x是一个宏形参,那么#就是转换为字符串x的形参名。这个过程称为字符串化。

#define PSQR(X) printf("The square of X is %d.\n", ((X)*(X)));
PSQR(8); 
The square of X is 64.  //此宏的双引号字符串中的X被视为普通文本,而不是一个可被替换的记号。

#define PSQR(x) printf("The square of " #x " is %d.\n", ((x)*(x)));
PSQR(y);
PSQR(2 + 4);
The square of y is 25.      //用"y"替换#x
The square of 2 + 4 is 36.  //用"2 + 4"替换#x

4.预处理粘合剂:##运算符
##运算符可用于类函数宏的替换部分,还可用于类对象宏的替换部分。##运算符把两个记号组合成一个记号。

#define XNAME(n) x ## n
#define PRINT_NX(n) printf("x"#n " = %d\n", x ## n);
int XNAME(1) = 14;  // 变换成int x1 = 14
PRINT_NX(3);        // 变换成printf("x3 = %d\n", x3);

PRINT_NX宏用#运算符组合字符串,##运算符把记号组合为一个新的标识符。

5.变参宏和__VA_ARGS__
一些函数(如printf())接受数量可变的参数。stdvar.h头文件提供了工具,让用户自定义可变参数的函数。C99/C11也对宏提供了这样的工具。
通过宏参数列表中最后的参数写成省略号(即...)来实现这一功能。这样,预定义宏__VA_ARGS__可用在替换部分中,表明省略号代表什么。

#define PR(...) printf(__VA_ARGS__)
PR("Howdy");                                    //宏展开后有一个参数printf("Howdy");
PR("weight = %d, shipping = $%.2f\n", wt, sp);  //宏展开后有三个参数printf("weight = %d, shipping = $%.2f\n", wt, sp);

#define PR(X, ...) printf("Message " #X ": " __VA_ARGS__)
double x = 48;
double y;
y = sqrt(x);
PR(1, "x = %g\n", x);   //宏展开后printf("Message 1: x= %g\n", x),最终输出Message 1: x = 48
PR(2, "x = %.2f, y = %.4f\n", x, y);  //Message 2: x = 48.00, y = 6.9282

posted on 2021-11-07 18:05  SOC验证工程师  阅读(551)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3