带参数的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

相关文章

发表新评论