gpt4 book ai didi

c - c中类似宏的函数

转载 作者:行者123 更新时间:2023-11-30 18:44:30 25 4
gpt4 key购买 nike

我有一些带有宏函数的 C 代码,但我无法理解其输出,

#define COMP(A,B) ( ((A) * (A)) + ((B) * (B)) )
int main()
{
int x = 2, y= 3, z;
z= COMP(x++,++y);
printf("x = %d\n", x);
printf("y = %d\n", y);
printf("z = %d\n", z);
}

在不同编译器上的输出是 4 5 31,有人可以说明原因吗?

最佳答案

代码未定义

宏调用COMP(x++,++y)扩展为

( ((x++) * (x++)) + ((++y) * (++y)) )

当我们有一个表达式或子表达式时

x++ * x++

如果同一个变量 x 被修改两次,则没有规则规定哪个修改先发生。 (在你问之前:不,括号不会改变任何东西,优先级也不会改变。)因此,编译器不必以这种或另一种方式执行此操作,这就是使代码未定义的原因:编译器不这样做根本不必做任何合理的事情,因为您不应该编写一开始就未定义的代码。

有关完整的故事,请参阅规范问题 Why are these constructs using pre and post-increment undefined behavior?

这就是为什么必须谨慎使用“类函数”宏(例如 COMP())或根本不使用的原因之一。基本上有三个规则:

  1. 将宏定义中的所有参数括起来
  2. 将整个定义放在括号内
  3. 一般来说,不要对有副作用的参数调用宏

COMP 宏的定义遵循规则 1 和 2,但调用 COMP(x++,++y) 显然违反了规则 3。

另请参阅问题 question 10.1在旧C FAQ list .

对于大多数(如果不是全部)类函数宏的使用,内联函数是更可取的。如果你写了

inline int comp(int x, int y) { return x*x + y*y; }

我认为你会得到更明智的结果。内联函数需要像常规函数调用一样评估其参数,因此在这种情况下,当您调用 comp(x++,++y) 时,您只会得到一个 x++ ,并且一个 ++y,意味着没有未定义的行为,并且有明确定义的结果。

<小时/>

作为另一个可能感兴趣的点,我在生产代码中看到了这个问题的一个版本,而且是在一种令人惊讶的自然、不做作的情况下出现的。想象一下您正在编写一个基于堆栈的小型算术计算器。暂时忽略堆栈溢出检测,您可能会从类似的内容开始

int stack[50];
int *stackp = stack;

#define Push(val) (*stackp++ = (val))
#define Pop() (*--stackp)

然后你可以使用如下代码将一些数字压入堆栈

Push(10);
Push(20);

然后您可以实现算术运算符,将数字从堆栈中弹出,执行运算并推送结果。这里补充一下:

int x = Pop();
int y = Pop();
Push(x + y);

但您几乎立即意识到,谁需要这些临时变量?,然后您将其“简化”为

Push(Pop() + Pop());

但这不起作用,它会给你奇怪的结果,原因是它扩展到

(*stackp++ = ((*--stackp) + (*--stackp)));

这是未定义的。 (我记得在 2003 年左右帮助一位同事在他的代码中找到了这个确切的问题。)

关于c - c中类似宏的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57828282/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com