Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何正确展开此宏?_C++_C_Macros - Fatal编程技术网

C++ 如何正确展开此宏?

C++ 如何正确展开此宏?,c++,c,macros,C++,C,Macros,定义此宏时: #define SQR(x) x*x 让我们这样说: SQR(a+b) ++SQR(a+b) 此表达式将被宏替换,如下所示: a+b*a+b 但是,如果我在表达式前面加上++运算符: SQR(a+b) ++SQR(a+b) 现在这个表达式是什么样子的?是否将此++放置在SQR参数的每个部分之前?像这样: ++a+b*++a+b 这里我给出一个简单的程序: #define SQR(x) x*x int a, k = 3; a = SQR(k+1) // 7 a = ++

定义此宏时:

#define SQR(x) x*x
让我们这样说:

SQR(a+b)
++SQR(a+b)
此表达式将被宏替换,如下所示:

a+b*a+b
但是,如果我在表达式前面加上
++
运算符:

SQR(a+b)
++SQR(a+b)
现在这个表达式是什么样子的?是否将此
++
放置在SQR参数的每个部分之前?像这样:

++a+b*++a+b
这里我给出一个简单的程序:

#define SQR(x) x*x
int a, k = 3;
a = SQR(k+1) // 7
a = ++SQR(k+1) //9

定义宏时,基本上总是希望将宏参数放在parens中,以防止第一个示例中出现这种奇怪的行为,并将结果放在parens中,这样就可以安全地使用,而不会产生副作用。使用

#define SQR(x) ((x)*(x))
使
SQR(a+b)
扩展到
((a+b)*(a+b))
,这在数学上是正确的(不同于
a+b*a+b
,它等于ab+a+b)

将内容放在宏之前或之后不会进入宏。因此,在您的示例中,
++SQR(x)
变成了
++x*x

注意以下几点:

int a=3, b=1;
SQR(a+b) // ==> a+b*a+b = 3+1*3+1 = 7
++SQR(a+b) // ==> ++a+b*a+b ==> 4 + 1*4 + 1 = 9
           // since preincrement will affect the value of a before it is read.
您会看到
++SQR(a+b)
似乎增加了2,因为在
a
之前,预增量开始生效,即
a
增量,然后使用两次,因此结果比预期高2


注@JonathanLeffler指出,后一个调用调用未定义的行为;评估不保证从左到右进行。它可能会在不同的编译器/操作系统上产生不同的结果,因此永远不应该依赖它。

定义宏时,基本上总是希望将宏参数放在parens中,以防止第一个示例中出现这种奇怪的行为,并将结果放在parens中,这样就可以安全地使用,而不会产生副作用。使用

#define SQR(x) ((x)*(x))
使
SQR(a+b)
扩展到
((a+b)*(a+b))
,这在数学上是正确的(不同于
a+b*a+b
,它等于ab+a+b)

将内容放在宏之前或之后不会进入宏。因此,在您的示例中,
++SQR(x)
变成了
++x*x

注意以下几点:

int a=3, b=1;
SQR(a+b) // ==> a+b*a+b = 3+1*3+1 = 7
++SQR(a+b) // ==> ++a+b*a+b ==> 4 + 1*4 + 1 = 9
           // since preincrement will affect the value of a before it is read.
您会看到
++SQR(a+b)
似乎增加了2,因为在
a
之前,预增量开始生效,即
a
增量,然后使用两次,因此结果比预期高2


注@JonathanLeffler指出,后一个调用调用未定义的行为;评估不保证从左到右进行。它可能会在不同的编译器/操作系统上产生不同的结果,因此永远不应该依赖它。

宏定义只是替换代码,因此通常最好放在括号中,否则代码可能会以您不希望的方式被替换

因此,如果您将其定义为:

#define SQR(x) ((x)*(x))
然后

++SQR(a+b)=++((a+b)*(a+b))


宏定义只是替换代码,因此通常最好放在括号中,否则代码可能会以您不希望的方式被替换

因此,如果您将其定义为:

#define SQR(x) ((x)*(x))
然后

++SQR(a+b)=++((a+b)*(a+b))


在您的示例中,
++SQR(a+b)
应扩展为
++a+b*a+b

因此,如果a==3和b==1,那么如果编译器从左到右对其求值,您将得到答案
9


但是您的语句
++SQR(3+1)
不正确,因为它将扩展为
++3+1*3+1
,其中
++3
无效。

在您的示例中,
++SQR(a+b)
应扩展为
++a+b*a+b

因此,如果a==3和b==1,那么如果编译器从左到右对其求值,您将得到答案
9


但是您的语句
++SQR(3+1)
不正确,因为它将扩展为
++3+1*3+1
,其中
++3
无效。

在预处理器中,它的计算结果为++a+b*a+b。正确的方法是用括号括住每个词和整个词,如:

#define SQR(x)  ((x)*(x))

在预处理器中,它的计算结果为++a+b*a+b。正确的方法是用括号括住每个词和整个词,如:

#define SQR(x)  ((x)*(x))

对于C++,正确定义宏的方法是不使用宏,而是使用:

template<typename T> static T SQR( T a ) { return a*a; }

使用函数形式,
++a
将被评估一次。在宏形式中,当您在序列点之间(至少对于C++)修改和读取值时,得到未定义的行为,对于C++来说,正确定义宏的方法是不使用宏,而是使用:

template<typename T> static T SQR( T a ) { return a*a; }

使用函数形式,
++a
将被评估一次。在宏形式中,当您在序列点之间多次修改和读取一个值(至少对于C++)时,会出现未定义的行为。

当您说
++SQR(3+1)
时,您如何知道它是9<代码>++3不应该编译。@克里斯,你说得对。我编辑了我的问题。现在我忘记了
++k*k
是否未定义。记住宏代替文本。您的行为将变成
++k+1*k+1
++k*k
是未定义的行为。不要去那里。++SQR(x)似乎是个坏主意,因为它的行为完全取决于SQR宏最后放在它旁边的内容。但正如尼诺的回答所说,++不会被扩展,宏非常简单(而且很危险),而且它们不注意周围的环境。当你说
++SQR(3+1)
,你怎么知道它是9<代码>++3不应该编译。@克里斯,你说得对。我编辑了我的问题。现在我忘记了
++k*k
是否未定义。记住宏代替文本。您的行为将变成
++k+1*k+1
++k*k
是未定义的行为。不要去那里。++SQR(x)似乎是个坏主意,因为它的行为完全取决于SQR宏最后放在它旁边的内容。但正如nneonneo的回答所说,++不会被扩展,宏非常简单(而且很危险),它们不注意周围的环境。温和的挑战性问题:您能想到这样一种情况吗?在这样一个示例中,有必要在宏参数名称周围添加括号:
#define macro(a,b)