C编程#定义?

C编程#定义?,c,macros,undefined-behavior,C,Macros,Undefined Behavior,可能重复: #包括 #包括 #定义SQ(x)x*x void main() { int a1、a2; int b1,b2; a1=2; a2=2; b1=0; b2=0; b1=SQ(a1++); b2=平方(++a2); printf(“第一次=%d”,b1); printf(“第二个=%d”,b2); } 我知道代码的输出是什么 在其他程序中定义工作 这样,在上述代码中就不起作用了 为什么?同一变量上有多个++运算符的表达式的结果在C中正式称为未定义行为。,因为define只是替换表达式

可能重复:

#包括
#包括
#定义SQ(x)x*x
void main()
{
int a1、a2;
int b1,b2;
a1=2;
a2=2;
b1=0;
b2=0;
b1=SQ(a1++);
b2=平方(++a2);
printf(“第一次=%d”,b1);
printf(“第二个=%d”,b2);
}
我知道代码的输出是什么

在其他程序中定义工作 这样,在上述代码中就不起作用了
为什么?

同一变量上有多个++运算符的表达式的结果在C中正式称为未定义行为。

,因为define只是替换表达式。所以你得到的结果是:

b1 = (a1++)*(a1++);
b2 = (++a2)*(++a2;

所以,你得到两倍的增量。它会导致未定义的行为。

SQ的两种用法都会调用未定义的行为,因为它们会在每个序列点多次分配给a1和a2。不应将带有副作用(如赋值或增量)的表达式传递给宏。

将宏中的操作数括在括号之间:

#define SQ(X) (X)*(X)
另外,尽量不要在同一个赋值中使用x++和x。可能导致未定义的行为

干杯

#define
是对预处理器的一条指令,用于用宏的展开形式替换宏的每次出现。因此,代码中的相关行将作为以下内容传递给编译器:

b1 = a1++ * a1++;
b2 = ++a2 * ++a2;

正如Seva所说,这些表达在官方上没有定义;但即使我们采用可以说是最明智的阅读方法,你仍然会得到
b1=2*3
b2=3*4(行后将
a1
a2
设置为4。

查看代码,因为预处理器将对其进行扩展:

b1 = a1++ * a1++;
b2 = ++a2 * ++a2;
这是未定义的行为,因为您多次修改变量时,变量之间没有序列点。

b1 = SQ(a1++);
b2 = SQ(++a2);
扩展到

b1 = a1++ * a1++;
b2 = ++a2 * ++a2;
调用未定义的行为(一个对象的值在序列点之间最多修改一次),这意味着任何结果都被认为是“正确的”

这就是这类宏的问题所在;您确实希望参数被计算一次,但由于扩展,它会被计算两次

用这样的表达式调用它也有问题

x = SQ(a + b);
这将扩展到

x = a + b * a + b;
这可能不是您想要的。为了保持运算符优先级,扩展应该包装在
()
中,例如

#define SQ(x) (x) * (x)

我真的不知道你的问题是什么,但也许你的预期产出有问题。。。 请注意,
#define
是在代码编译之前运行的“简单”文本替换。 此文本替换不考虑范围或语法更正。它只替换与您所说内容匹配的任何内容。 在您的例子中,它实际上不会与“a++”的结果成平方,相反,它会 生成此代码:b1=a++*a++


如果你看这里:你可以看到一些解释,比如为什么“a++*a++”是官方未定义的行为。

祝贺您!您刚刚发现为什么在这类事情上使用宏是一个坏主意。一般来说,只有在无法使用函数的情况下,才将某件事情设置为宏。在这种情况下,
SQ
可以轻松地作为函数实现:

int sq (int x)
{
    return x * x;
}

编译和执行时会发生什么?错误?奇怪的结果?什么?您期望的输出是什么,您得到的是什么?我非常确定,在x++*x++和+++y*++y*中,在计算第二个增量时,第一个增量是否已经发生是未定义的,因此在or中,您得到的值将因环境而异最初的问题是,有一个打字错误(
#deifne
,而不是
#define
)我现在更正了,请确保您使用的代码是正确的。您在扩展中添加了一些括号。在这种情况下,这没有任何区别,但有时会产生巨大的差异。@Darron同意您的观点。为了可读性,这在技术上是“未定义的行为”吗?我认为这是“未指定的行为”,这仍然很糟糕,但将实现限制在某些选择上(在本例中不包括崩溃)。是的,它肯定是未定义的;)。顺便说一句,这个答案并不完全正确。一个表达式可以多次修改同一个变量-只有在这些修改之间没有序列点(即&&、| |、?:、逗号运算符或函数调用)语言律师(我不是:)也没有在电视上播放时,行为才是未定义的,您还需要将整个表达式用括号括起来,即
#define SQ(x)((x)*(x))
否则像
x=-SQ(4)
这样的表达式可能会给出意外的结果。@JeremyP:oops,是的,您是对的。你能告诉我,我不经常使用这样的宏吗?+ 1比C++语言更重要。
int sq (int x)
{
    return x * x;
}