带参数的c语言宏定义
定义的含义
C语言中的宏定义就是定义外部变量和内部函数被exit imer调用。
如:exiterm char c1,C2;
C语言中宏定义的词是:定义。
C语言中定义宏定义有两种形式:带参数和不带参数。
不带参数的格式为:#定义宏名字符串。
带参数的格式为:#定义宏名(参数1,参数2,...)字符串。
在C语言中,宏定义只是用来替换宏名,没有语法检查,所以不是C语句,所以不需要加“;”宏定义之后。
宏在C中也被称为预处理命令,因为宏在程序编译前替换字符,所以被称为预处理。C中还有其他预处理命令,例如:
#定义
#undef
#ifdef
等等
定义in c语言的用法 C语言中define的用法(2009-08-17 19:21:11)转载标签:漫谈
Define是C语言中的预处理命令。用于宏定义,可以提高源代码的可读性,为编程提供方便。
预处理命令以“#”开头,比如包含命令#include,宏定义命令#define等。一般放在源文件的前面,称为预处理部分。
所谓预处理,是指编译前所做的工作。预处理是C语言的一个重要功能,由预处理器来完成。编译源文件时,系统会自动引用预处理器对源文件的预处理部分进行处理,处理后自动进入源文件的编译。
宏的定义
在C或C语言的源程序中,允许用一个标识符来表示一个字符串,称为宏。定义为宏的标识符称为宏名。在编译和预处理时,程序中所有的“宏名”都被替换为宏定义中的字符串,称为“宏替换”或“宏扩展”。宏定义是由源程序中的宏定义命令完成的。宏替换由预处理程序自动完成。
在C或C语言中,“宏”可分为参数型和非参数型两种。
无参数宏定义
没有参数的宏就是没有参数的宏,它的一般定义是:
#定义标识符字符串
标识符是定义的宏名。“字符串”可以是常数、表达式、格式字符串等。
例如:
#定义PI 3.14
它的功能是指定标识符PI而不是常数3.14。写源程序的时候,所有用到3.14的地方都可以用PI代替,而编译源程序的时候,预处理器会把所有的宏名都用3.14代替,然后再编译。
宏定义就是用宏名来表示一个字符串,然后在宏展开的时候用这个字符串替换宏名。这只是一个简单的替换。该字符串可以是常量,也可以是表达式,预处理程序不会检查它。如果有错误,只有在编译被宏展开的源程序时才能发现。
宏定义不是描述或语句(是预处理指令),不需要在行尾加符号。如果加上分号,连分号都会被替换。
下面是一个非参数宏替换常数的示例:
#定义PI 3.14
#包括
int main()
{
浮点r = 1.0
浮动面积= PI * r * r
printf("圆的面积是%f ",面积);
返回0;
}
使用无参数宏代替字符串的另一个例子:
#定义M(y * y ^ 3 * y)
#包括
int main()
{
int s,y;
printf("输入一个数字:");
scanf("%d ",y);
s = 3 * M 4 * M 5 * M
printf("s=%d\n ",s);
返回0;
}
# define M (y*y 3*y)定义M表达式(y*y 3*y)。写源程序时,所有(y * y ^ 3 * y)都可以用m代替,而编译源程序时,会先用预处理程序进行宏替换,即所有宏名m都用(y * y ^ 3 * y)表达式代替,然后再进行编译。
在上面的例子中,先定义了宏,定义了M表达式(y * y ^ 3 * y),在S = 3 * m 4 * m 5 * m中进行宏调用,预处理时宏展开后,句子变成:S = 3 *(y * y ^ 3 * y)4 *(y * y ^ 3 * y)5 *(y * y ^ 3 * y);但需要注意的是,在宏定义中,表达式(y * y 3 * y)的括号不能少。否则,将会出现错误。
带参数的宏定义
c语言允许宏带参数。宏定义中的参数叫形参,宏调用中的参数叫实参。对于带参数的宏,不仅要扩展宏,还要用实参数代替形参数。
带参数的宏定义的一般形式是:
#定义宏名(参数表)字符串
每个参数都包含在字符串中。
带参数的宏调用的一般形式是:
宏名(参数表)
例如:
#定义M(y) y*y 3*y
....
k = M(5);
....
调用宏时,用自变量5代替形参y,预处理宏展开后的语句为:
k=5*5 3*5
举一个具体的例子:
#定义MAX(a,b) (ab)?甲:乙
#包括
int main()
{
int x,y,max
printf("输入两个数:");
scanf("%d%d ",x,y);
max = MAX(x,y);
printf("max=%d\n ",max);
返回0;
}
上述示例程序的第一行定义了一个带参数的宏,条件表达式(ab)用宏名MAX表示。A:b,形参A和B都出现在条件表达式中。程序的第七行max = MAX(x,y)是一个宏调用,实参x,y会代替形参a,b,宏展开后的语句是:max = (xy)?x:y;用于计算x,y中的大数。
对于带参数的宏定义,需要解释以下问题:
1.在带参数的宏定义中,宏名和参数表之间不能有空格。
比如:#定义MAX(a,b) (ab)?A:b写成#define MAX (a,b) (ab)?A:b会被认为是没有参数的宏定义,宏名MAX代表字符串(a,b)(ab)?甲:乙.
扩展宏时,宏调用语句:max = MAX(x,y);会变成:max = (a,b)(ab)?a:b(x,y);这显然是错误的。
2.宏定义中的形参是标识符,而宏调用中的实参可以是表达式。
#定义SQ(y) (y)*(y)
#包括
int main()
{
int a,sq;
printf("输入一个数字:");
scanf("%d ",a);
SQ = SQ(a1);
printf("sq=%d\n ",sq);
返回0;
}
在上面的例子中,定义了第一个行为宏,形参是y,程序第七行宏调用中的实参是1,是一个表达式。当宏展开后,用1代替Y,再用(y)*(y)代替SQ,得到如下语句:SQ =(a1)*(a1);这与函数调用不同,函数调用时要找出实参表达式的值,然后给出形参。在宏替换中,直接按原样替换实参数表达式,无需计算。
3.在宏定义中,字符串中的形参通常用括号括起来,以避免出错。在上面例子的宏定义中,( y)*(y)表达式的y用括号括起来,结果是正确的。如果删除了括号,请将程序更改为以下形式:
#定义SQ(y) y*y
#包括
int main()
{
int a,sq;
printf("输入一个数字:");
scanf("%d ",a);
SQ = SQ(a1);
printf("sq=%d\n ",sq);
返回0;
}
运行结果是:输入一个数字:3。
Sq=7(预期结果是16)。
有什么问题?这是因为替代只是符号替代,没有其他处理。宏替换后,会得到如下语句:sq = a 1 * a 1因为a是3,所以sq的值是7。这显然和问题的意思相反,所以参数两边的括号是不可或缺的。有时,甚至在参数两边加上括号也是不够的。请参见以下步骤:
#定义SQ(y) (y)*(y)
#包括
int main()
{
int a,sq;
printf("输入一个数字:");
scanf("%d ",a);
SQ = 160/SQ(a1);
printf("sq=%d\n ",sq);
返回0;
}
和前面的例子相比,这个程序只是把宏调用语句改为:SQ = 160/SQ(a 1);运行这个程序时,如果输入值仍然是3,那么预期的结果是10。但实际操作的结果是:输入一个数字:3 sq=160。
为什么会有这个结果?分析宏调用语句,宏替换后变成:sq = 160/(a1)*(a1);当a为3时,由于“/”和“*”运算符的优先级和组合相同,先做160的40/(3 ^ 1),再做40 *(3 ^ 1),最后得到160。为了得到正确的答案,在宏定义中要给整个字符串加上括号,程序修改如下:
#定义SQ(y) ((y)*(y))
#包括
int main()
{
int a,sq;
printf("输入一个数字:");
scanf("%d ",a);
SQ = 160/SQ(a1);
printf("sq=%d\n ",sq);
返回0;
}
上面的讨论表明,对于宏定义,不仅在参数两边放括号是安全的,在整个字符串上也是安全的。
4.带参数的宏与带参数的函数非常相似,但本质上是不同的。用函数和宏处理同一个表达式的结果可能不同。
这里有一个比较的例子:
使用该功能:
#包括
int SQ(int);
int main()
{
int I = 1;
while(i=5)
printf("%d\n ",SQ(I));
返回0;
}
int SQ(int y)
{
return((y)*(y));
}
使用宏:
#定义SQ(y) ((y)*(y))
#包括
int main()
{
int I = 1;
while(i=5)
printf("%d\n ",SQ(I));
返回0;
}
在使用函数的例子中,函数名是SQ,形参是y,函数体表达式是((y)*(y))。在使用宏的例子中,宏名是SQ,形参是y,字符串表达式是(y)*(y))。两种情况表面是一样的,函数调用是SQ(i),宏调用是SQ(i),参数也是一样的。但输出结果差别很大,分析如下:
在使用函数的例子中,函数调用是将实参数I的值传递给形参数Y,然后加1。然后输出函数值。所以要循环五次。输出1 ~ 5的平方值。在使用宏的例子中,当宏被调用时,它们只是被替换。SQ(i)替换为((i )*(i))。在第一个循环中,因为I等于1,所以它的计算过程是:表达式中前一个I的初始值是1,然后I从1增加到2,所以表达式中第二个I的初始值是2,两个相乘的结果也是2,然后I的值从1增加到3。第二个周期,I的初始值是3,所以前一个I是3,后一个I是4,乘积是12,然后I从1增加到5。进入第三个循环,因为I值已经是5,所以这将是最后一个循环。计算表达式的值是5*6等于30。I的值从1增加到6,不再满足循环条件,循环停止。从上面的分析可以看出,函数调用和宏调用在形式上是相似的,但在本质上是完全不同的。
" \ "、" # "、" # @ "和" # # "
当用#define定义时,斜杠(" \ ")用于继续该行,而“#”用于将参数转换为字符串,双引号被添加到参数中。“# #”用来连接前后两个参数,并把它们变成一个字符串。“# @”是给参数加上单引号。下面的例子会让你很容易理解。
#定义Conn(x,y) x##y
#define ToChar(a) #@a
#定义ToString(x) #x
int n = Conn(123,456);结果是n = 123456
Char* str = Conn("asdf "," adf ")结果是str = " asdfadf
char a = to char(1);结果是a = ' 1
char * str = ToString(123132);就变成str = " 123132
为什么需要“#”、“# @”和“# #”这三个运算符?原因如下:
如果源程序中的宏名用引号括起来,预处理器不会替换它。如下所示:
#定义OK 100
#包括
int main()
{
printf(" OK ");
printf(" \ n ");
返回0;
}
在上面的例子中,宏名OK被定义为100,但是在printf语句中OK用引号括起来,所以没有进行宏替换。程序的运行结果是:OK,这意味着“OK”被当作一个字符串。
同样,如果源程序中的宏名用单引号括起来,预处理器也不会替换它。
宏定义的嵌套
宏定义允许嵌套,已定义的宏名可以在宏定义字符串中使用。当宏被展开时,它被预处理程序逐层替换。例如:
#定义PI 3.1415926
#定义S PI*y*y
相反的语句:printf("%f ",s);
宏替换后变成:printf("%f ",3.1415926 * y * y);
结束语
用宏代替程序中经常用到的常量,这样当常量发生变化时,不需要修改整个程序,只需要修改宏定义的字符串即可,当常量较长时,我们可以用更短的有意义的标识符来编写程序,这样更方便。举个大家熟悉的例子,圆周率是数学中常用的数值,有时候我们会用3.14,有时候会用3.1415926等等。,这取决于计算所需的精度。如果我们想在一个程序中多次使用它,我们需要确定一个值,这个值在这个运算中不会改变,但是可能后来我们发现程序表达的精度变了,我们需要改变它的值。需要修改程序中所有的相关值,这给我们带来了一些不便。但是如果用宏定义代替标识符,那么修改的时候只能修改宏定义,也可以减少输入3.1415926这样长的值的次数。我们可以这样定义# definepi3.45926,这样既减少了输入又方便了修改。为什么不呢?
另外,使用带参数的宏定义可以完成函数调用的功能,减少系统开销,提高运行效率。正如C语言中所述,函数的使用可以使程序更加模块化,易于组织和重用。但是调用一个函数时,需要保留调用该函数的场景,以便子函数执行后返回继续执行。类似地,在执行子功能后,需要一些时间来恢复调用该功能的场景。如果子函数执行许多操作,则可以忽略这种转换时间开销。但是如果子函数完成的函数比较少,甚至只完成一点点运算,比如一个乘法语句的运算,这部分转换开销会比较大,但是使用带参数的宏定义就不会出现这个问题,因为是预处理阶段的宏展开,执行时不需要转换,也就是本地执行。宏定义可以完成简单的操作,但是复杂的操作还是需要通过函数调用来完成,宏定义占用了比较大的目标代码空间。所以在使用宏定义时需要根据具体情况来决定是否使用宏定义。
c语言定义一个带参数的宏,求两个整数的余数,通过宏调用输出计算结果。 #包括iostream
使用命名空间std
#定义虞丘(a,b){ a % = b;}
char a[10000];
int main()
{
int x,y;
cinxy
如果(y!=0)
虞丘(x,y)
coutx
}
操作效果:
扩展数据:
scanf函数的语法规则:
1.语法
#包含stdio.h
int scanf(const char *格式,...);
类似的功能有
int scanf(const char *格式,...);
int fscanf(FILE *stream,const char *format,...);//固定输入流
int sscanf(const char *str,const char *format,...);//指定缓冲区
2.规则
scanf()函数根据format指定的格式从stdin(标准输入)中读取数据,并将数据保存到其他参数中。它有点类似于printf()。格式字符串由控制字符、空白字符和非空白字符组成。控制字符以%符号开始。
参考资料:
百度百科-scanf
最后更新于 2023-10-10 22:32:53 并被添加「」标签,已有 位童鞋阅读过。
本站使用「署名 4.0 国际」创作共享协议,可自由转载、引用,但需署名作者且注明文章出处
相关文章