0
点赞
收藏
分享

微信扫一扫

程序的操作(预处理)第二部分

皮皮球场 2022-04-16 阅读 57
c语言

四、预定义符号介绍

上面这些代码都是C语言内置的代码。

下面重点介绍#define和#include这两个预处理指令

 #define

1、#define可用于定义某些标识符,可以在一定程度上增加代码的可读性。

举个例子:

#define MAX 100

这样所有需要100的地方都可以用MAX来替代。#define定义的标识符甚至可以是一段代码,这是C允许的。

注意:不要在#define语句后随意添加分号,否则会出现错误,如:

#define M 100;
int main()
{
int a = M;
return 0;
}

 这时编译器会认为分号也是标识符的一部分,替换后的a就变成了 100;;从而产生了错误,所以不要在#define语句后面随便加上分号!

2、#define定义宏

#define定义宏的具体方式是:

#define name( parament - list ) stuff, 其中的name是宏名称, parament - list 是一个由逗号隔开的符号表,stuff是语句项。

注意:符号表外面的括号必须紧贴name,否则会被解析为stuff的一部分。

例: #define Add(a,b) a+b

#define定义的宏有一个非常易错的地方(反正我是错了好几次),就是宏定义的参数是直接替换上去的,有时甚至没考虑运算符之间的运算顺序。

比如:

#define SQUARE(X) X*X
int main()
{
int a = 5;
int b = SQUARE(a+1);
printf("%d",b);//打印的结果是什么?
return 0;
}

或许你会说代码的结果是36,那恭喜你,答错了~ 打印的结果是11,为什么呢?

因为#define定义宏是将参数直接替换,并不是将参数中表达式的结果运算完再代入,这个代码中替换完b = a+1*1+a 所以应该是5+1*1+5 = 11,并不是36。

如果我们想要刚开始我们猜测的结果,就应该在宏定义内的X两边加上括号——

#define SQUARE(X) (X)*(X)
int main()
{
int a = 5;
int b = SQUARE(a+1);
printf("%d",b);
return 0;
}

但是这样还是有问题,比如将b后面的语句修改为

#define PLUS(X) (X)+(X)
int main()
{
int a = 5;
int b = 10*PLUS(a);
printf("%d",b);
return 0;
}

好吧,这个代码的结果也并不是我们所预期的100,而是55,这是因为宏替换完的结果是10*5+5=55,如果我们需要得到100,应做如下的修改:

#define PLUS(X)  ((X)+(X) )//多加上一对括号
int main()
{
    int a = 5;
    int b = 10*PLUS(a);
    printf("%d",b);
    return 0;
}

讲了这么多,总结一句话就是写宏定义语句时候一定不要吝啬自己的括号,否则就会出现不在预期内的结果。

#define的替换规则

 字符串常量中如果出现了#define定义的标识符,将不会被替换,因为字符串常量不可被修改。

 #和##的作用

 当字符串作为宏的参数时候,可以被直接替换进字符串内部,如

#define PRINT(FORMAT, VALUE)\
printf("the value is "FORMAT"\n", VALUE);
int main()
{
PRINT("%d", 10);
return 0;
}

PRINT的作用相当于 printf("the value is %d\n",10)。

#的作用能将任意参数转化为字符串放入字符串内,比如:

#define PRINT(FORMAT,VALUE)\
printf("the value of " #VALUE " is "FORMAT "\n", VALUE);

int main()
{
int i = 0;
PRINT("%d",i + 3);
return 0;
}

打印结果:

 如果没有#,打印的结果将会是:

字符串中的VALUE无法随着传入参数的变化而变化,一直都会是VALUE。 

##的作用是将两侧的分离字符和为一个字符

比如:
 

#define TEST(p,value)
sum##value = p;
int main()
{
int sum5 = 0;
TEST(10,5);
printf("%d",sum5);
return 0;
}

 

显然value是5的时候sum##value就变成了sum5,它在宏内被赋值为10,所以代码的结果是10。

宏显然是和函数有点相似的,那宏与函数各自的优缺点是什么呢?

对于一些比较小型的代码,我们常用宏来解决,比如:求两个数的较大值,求和,求商...

不用函数的原因是,函数的调用往往需要在栈上开辟空间,函数开辟栈帧的创建和销毁,往往需要占用空间和时间,不如宏来的效率高。

第二个原因是函数的参数是指定类型的,比如是double类型,那就只能求double类型数的较大值。而宏是不受参数限制的,也就是说宏是参数类型无关的。 

当然宏也是有一定缺点的:

 宏还能做到一些函数做不到的事情——宏的参数可以是类型,而函数不能。

这次的分享就到这,下次给大家分享条件编译的内容!

举报

相关推荐

0 条评论