首页 > 编程知识 正文

c语言带参数的宏定义,c语言宏定义是什么

时间:2023-05-05 00:47:46 阅读:155734 作者:3112

1 .预处理编译C语言程序的第一步是预处理阶段,此阶段是宏起作用的阶段。 C预处理器在编译源代码之前,删除注释、插入#include输入的文件内容、定义和替换#define定义的符号,以及代码部分的内容是否根据条件编译#if () “文本性质”的操作是指用另一个文本替换一个文本,与它的含义和内容无关。 宏只是c预处理阶段的文本替换工具,编译后不会显示在二进制代码中

2 .宏定义的用法宏常量我们最常用的#define用法是在#define中定义符号常数。 修改的时候,修改#define这个句子就可以了,不需要对每个代码进行修改

例:

# include ' stdio.h ' # define pi 3.14 # definestr '圆周率为' int main () ) printf(%s%f )、str、pi ); //预处理时替换为printf () %s%f ),)圆周率约),3.14 ); 返回0; }运行结果:

也可以在宏语句宏中定义一个或多个语句

例:

# include ' stdio.h ' # defineprintprintf (' hello world!' (int main ) ) {打印; //预处理时printf(Helloworld! )取代); 返回0; }操作结果:

也可以在宏函数宏中定义函数。 因为宏观定义也可以有参数

例:

# include ' stdio.h ' # define { print (str ) printf('%s ',str ) int main ) ) print )这只是一个语句的宏函数! ' ); //预处理时将替换为printf (。' %s ','这是只有一个语句的宏函数! ' )返回0; }

http://www.Sina.com/http://www.Sina.com /

#define PI 3.141592654…

//代码

#undef PI

//从下面开始PI失效

其它

这是宏观定义的一种,根据变量是否已经定义可以进行分支选择,一般用于调试等。 实际上,这应该是预处理功能中的三个(宏定义、文件包含、条件编译)之一的条件编译。 C语言在编译程序时,首先根据预处理指令进行“预处理”。 C语言编译系统包括预处理、编译、链接等部分。

#ifndef x //首先测试x是否由宏定义。 如果未定义#define x //宏,则宏定义x并编译以下语句: #endif //如果已定义,则用于编译#endif之后的语句的条件指示符#ifndef检查预编译常量是否由宏定义。 如果之前未在宏中定义,则条件指示符的值为true,并且编译过程中将包括#ifndef到#endif的所有语句。 相反,如果#ifndef指示符的值为假,则将忽略与#endif指示符之间的行。 条件指示符#ifndef的主要目的是防止头文件的重复包含和编译。

请不要忽略主题中的#ifndef。 这是重要的东西。 例如,有两个包含同一头文件的C文件。 在编译过程中,这两个c文件将一起编译为一个可执行文件。 于是发生了问题,大量的声明发生了冲突。

所以把头文件的内容放入#ifndef和#endif吧。 无论头文件是否被多个文件引用,都要添加它。 一般的格式如下。

#ifndef标记#define标记

.

#endif

虽然徽标在理论上可以自由命名,但每个头文件中的“徽标”必须是唯一的。 的命名规则通常为大写开头的文件名,前后加下划线,并将文件名中的“.”也更改为下划线。 例如stdio.h

#ifndef _STDIO_H_#define STDIO_H

.

如果未定义span class=' tokenmacroproperty ' # span class=' tokendirectivekeyword ' endif/span/span # ifndef XXX//XXX

#定义定义定义XXX//XXX

#endif //如果结束了

这种用法主要是头文件,主要是为了防止类重复的include,所以在类的头文件之前加上前面两个,然后在最后加上类名代替xxx

3358 WWW.Sina.com/http://WWW.Sina.com /

  我们定义宏语句或者宏函数时不可能总是一条语句呀,那要是有很多条语句时怎么办?都写在一行吗?这样显然代码就不美观,可读性不好,所以有多条语句时,我们就在每行末尾(除了最后一行)加上"",代表换行的意思
例:

#include"stdio.h"#define Print printf("这是第1条语句n"); printf("这是第2条语句n"); printf("这是第3条语句n")

#define Show(str1,str2,str3)
{
printf("%sn",str1);
printf("%sn",str2);
printf("%sn",str3);
}
int main()
{
Print; //无参数宏函数
Show(“first”,“second”,“third”); //带参数宏函数
return 0;
}

操作结果:

②字符串化符 "#"

  "#"是“字符串化”的意思,将出现在宏定义中的#是把跟在后面的参数转换成一个字符串
例:

#include"stdio.h"#define Print(str){printf(#str"的值是%d",str);}int main(){int x=3,y=4;Print(x+y); //此处等价于printf("x+y""的值是%d",x+y); //#str等价于"x+y",所以#str不需要再用双引号引起来 return 0;}

操作结果:


③片段连接符"##"

  “##”是一种分隔连接方式,它的作用是先分隔,然后进行强制连接。在普通的宏定义中,预处理器一般把空格解释成分段标志,对于每一段和前面比较,相同的就被替换。但是这样做的结果是,被替换段之间存在一些空格。如果我们不希望出现这些空格,就可以通过添加一些##来替代空格。
例:

#include"stdio.h"#define Add(n,value){num##n+=value; } int main(){int num1=1;int num2=10;Add(2,10); //等价于num2+=10; 这里把num和2连接成了num2 printf(" num1=%dn num2=%d",num1,num2); return 0;}
四.宏函数的巧用 ①类型传递

  我们知道函数虽然可以传递参数,但是却不能把类型作为参数传递,有时我们为了实现函数的复用性,就要使用STL模板,但是我们这个时候还有另外一种选择,就是写成宏函数
例:
一个开辟内存的函数

#define Malloc(type,size) (type*)malloc(sizeof(type)*size)

这个时候,我们只有把类型,容量作为参数传递进行,就可以开辟各种类型的内存了

int *p=Malloc(int,100); //开辟int类型的内存char *q=Malloc(char,100); //开辟字符类型的内存 ②传递数组

  由数组作为函数参数传递时,会失去其数组特性,也就是无法使用sizeof()函数计算出数组的大小,比如我们写一个排序函数,排序时我们不仅需要知道数组的首地址,还需要知道数组的大小,但是仅仅把数组名作为参数传递时,无法得知其数组大小,这时我们的函数就需要传递第二个参数,也就是数组的大小,于是函数就要写成Sort(int *a,int size).但宏函数就可以解决这个问题
例:
下面用宏函数写一个插入排序算法

#include"stdio.h"#define InsertSort(list){int s=sizeof(list)/4;int i,j;for(i=2;i<=s;i++){list[0]=list[i];for(j=i-1;list[j]>list[0];j--)list[j+1]=list[j];list[j+1]=list[0];} }int main(){int num[]={0,2,5,7,3,1,8,0,8,22,57,56,74,18,99,34,31,55,41,12,9,4};InsertSort(num);for(int i=1;i<sizeof(num)/4;i++)printf("%d ",num[i]);return 0;}

操作结果:

当然还有很多宏定义的巧妙用法,这里就不全部列举了

五.注意事项 ① 运算符优先级问题 #define MULTIPLY(x, y) x * y 1

  这是一个很简单的乘法函数,当计算MULTIPLY(10, 10),结果是100,这个大家都知道,但是rydxh计算MULTIPLY(5+5, 10)时,你以为结果还是100吗?当然不是,MULTIPLY(5+5, 10)=5+5*10=55,所以结果是55,所以我们写宏函数时要特别注意运算符的优先级,这里稳妥一点的写法应该这样写

#define MULTIPLY(x, y) ((x)*(y)) ②宏参数重复调用 #define MAX(a,b) ((a)>(b)?(a):(b))int a=0;int b =1;int c =MAX(++a,++b);

这里很多人都以为是c=MAX(1,2)=2;而实际上上面代码等价于

int c =((++a)>(++b)?(++a):(++b));

可以看到实际上a b都各自加了两次,所以c=1>2?2:3=3,所以结果是3

③分号吞噬问题 #include"stdio.h"#define FUN(n){while(n>0){if(n==3)break;}}int main(){int num=10;if(num>0)FUN(num);elsenum=-num;return 0;}

  看似代码没有问题,但是一编译就报错,编译器显示"error: ‘else’ without a previous ‘if’",原来是因为FUN函数是一个代码块,然后if(num>0) FUN(num); 就等价于if(num>0) {…}; 这不就是在大括号后面打分号了吗?这样else当然就缺少if了
  这个时候我们可以用do{…}while(0)来解决这个问题,写成如下就没问题了,因为while()后面正好需要一个分号

#define FUN(n) do{while(n>0){if(n==3)break;}}while(0) ④递归调用问题 #define NUM (4 + NUM)

  按前面的理解,(4 + NUM)会展开成(4 + (4 + NUM)),然后一直展开下去,直至内存耗尽。但是,预处理器采取的策略是只展开一次。也就是说,NUM只会展开成(4 + NUM),而展开之后NUM的含义就要根据上下文来确定了。

⑤宏参数预处理

  宏参数中若包含另外的宏,那么宏参数在被代入到宏体之前会做一次完全的展开,除非宏体中含有#或##。

有如下宏定义:

#define A(y) X_##y#define B(y) A(y)#define SIZE 1024#define S SIZE

A(S)会被展开成X_S。因为宏体中含有##,宏参数直接代入宏体。
B(S)会被展开成X_1024。因为B(S)的宏体是A(S),并没有#或##,所以S在代入前会被完全展开成1024,然后才代入宏体,变成X_1024。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。