C语言学习记录:宏定义:#define

C预处理器:在程序执行之前查看程序。根据程序中的预处理器指令,预处理器把符号缩写替换成其表示的内容。

预处理指令示例:

#define、#include、#ifdef、#else、#endif、#ifndef、#if、#elif、#line、#error、#pragma

ANSI和后来的标准都允许 # 前面有空格或者制表符,而且还允许在 # 和指令的其余部分之间有空格。


目录

#define

记号问题

类函数宏

用宏参数创建字符串:#运算符

预处理器黏合剂:##运算符

变参宏:...和__VA_ARGS__


#define

程序示例:

以下定义都是被允许的!

#include <stdio.h>
#define TWO 2
#define OW "Consistency is the last refuge of the unimagina\
tive. -Oscar Wilde"                    //反斜杠表示切换到下一行
#define FOUR = TWO*TWO
#define PX printf("X is %d.\n",x)
#define FMT "X is %d.\n"

int main(void)
{    
    int x = TWO;
    PX;
    x = FOUR;
    printf(FMT,x);
    printf("%s\n",OW);     //这里输出的是代表的字符串!
    printf("TWO:OW\n");    //这里输出的是:TWO:OW,而不是其代表的字符串和数组!
}

拿出一个逻辑行当例子说明:

#define TWO 2

#define 是预处理器指令,TWO 是选定的缩写,也成为2 称为替换列表或替换体。

有些宏代表值,称为类对象宏(object-like macro),还有类函数宏(function-like macro)

在宏定义中,还可以包含其他宏。


记号问题

把宏的替换体看做是记号(token)型字符串,而不是字符型字符串。

#define FOUR 2*2

只有一个记号:2*2 序列

#define SIX 2 * 3

这个宏定义有三个记号:2*3

假设编译器解释为字符型字符串,将用 2 * 3 替换 SIX 。即额外的空格是替换体的一部分。

编译器解释为记号型字符串,则用3个的记号 2 * 3 (分别由单个空格分隔)来替换 SIX 。

解释为字符型字符串:把空格视为替换体的一部分。解释为记号型字符串:把空格视为替换体中各记号的分隔符。


类函数宏

在 #define 中使用参数可以创建外形和作用与函数类似的类函数宏。参数称为宏参数。

例子:

#define SQUIRE(x) x*x

#define SUM(x,y) x+y

//调用

sum = SUM(5,7);
squire = SQUIRE(9);

但是,函数宏只是替换并不是真正的函数!

//列如
SQUIRE(2+7)
//理想中应该是 81 ,但是实际上是 23

X = 100/SQUIRE(2)
//理想中应该是 25 ,但是实际上是 100

为什么出现这种状况?实际上的计算过程:

SQUIRE(2+7) = 2+7*2+7 = 23

X =100/SQUIRE(2) = 100/2*2 = 100

编程时应注意

#define SQUIRE(x) ((x)*(x))

用宏参数创建字符串:#运算符

引入例子:

#define PSQR(X) printf("The squire of X is %d.\n",((x)*(x)));
//使用宏:
PSQR(9);

//输出
The squire of X is 81.\n

此时 "" 中的 X 被视作普通文本,而不是可替换的符号。

字符串化(stringizing)

#define PSQR(X) printf("The squire of " #X " is %d.\n",((X)*(X)));

int main(void)
{
    int y = 5;
    
    PSQR(y);
    PSQR(2 + 4);

    return 0;
}

此时的输出为:

The squire of y is 25.

The squire of 2 + 4 is 36.


预处理器黏合剂:##运算符

与 # 运算符类似, ## 运算符可用于 类函数宏 的替换部分。而且, ## 还可以用于对象宏的替换部分。 ## 运算符把两个记号组成为一个记号。

such as:

#define XNAME(n) x ## n

XNAME(4)   //被编译器解释为x4 

## 作为黏合剂的使用:

#define XNAME(n) x ## n
#define PRINT(n) printf("X" #n " = %d\n",x ## n);

int main(void)
{
    int XNAME(1) = 14;    //解释为 int x1 = 14;
    int XNAME(2) = 20;
    int x3 = 30;
    PRINT(1);             //解释为 printf("x1 = %d\n",x1);
    PRINT(2);
    PRINT(3);
    return 0;
}

运行结果有:

x1 = 14

x2 = 20

x3 = 30

体会一下其中的含义吧 ~


变参宏:...和__VA_ARGS__

这个还是需要多考虑一下的!!

这个以前没注意过,读别人代码才发现有这么个东西,我真是沙雕了!

一些函数支持数量可变的参数。如printf() 。

用户可自定义带可变参数的函数,stdvar.h 头文件中提供了工具。

通过把宏参数列表中的最后的参数写成省略号来实现这一功能。这样,预定义宏__VA_ARGS__可用在替换部分中,表明省略号代表什么

#define PR(...) printf(__VA_ARGS__);

程序示例:

#include <stdio.h>
#include <math.h>

#define PR(X,...) printf("Message " #X ": "__VA_ARGS__)

int main(void)
{
    double x = 48;
    double y;        //y没定义是乱数
    
    y = sqrt(x);
    PR(1,"x = %g\n",x);                //printf("Message 1:x = %g\n",x);
    PR(2,"x= %.2f, y = %.4f\n",x,y);

    return 0;
}

输出:

Message 1: x = 48

Message 2: x = 48.00, y = 6.9282

省略符号只能代替最后的宏参数!!!!

最后,宏名中不允许出现空格!!!在嵌套循环中使用宏定义的函数有助于提高效率,单词循环看不出来效果。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值