使用带有参数的宏时出现意外结果 [duplicate]

Getting unexpected results when using macros with arguments [duplicate]

提问人:Kanishk 提问时间:10/27/2023 最后编辑:Vlad from MoscowKanishk 更新时间:10/28/2023 访问量:101

问:

#include <stdio.h>
#define big(a, b) a > b ? a : b
#define swap(a, b) temp = a; a = b; b = temp;

int main() {
    int a = 3, b = 5, temp = 0;
    if ((3 + big(a, b)) > b)
        swap(a, b);
    printf("%d %d", a, b);
}

上面的代码是在多项选择题中给出的。 我以为答案是 5 3。在运行代码时,输出为 5 0。我试图理解这一点,但我的努力是徒劳的。这段代码的工作原理是什么?

c 交换 条件运算符 预处理器指令

评论

2赞 Marek R 10/27/2023
在 C++ 中,使用宏被认为是一种不好的做法
1赞 Kanishk 10/27/2023
原始问题也没有括号。我想知道这句话是如何改变程序的。@YSC
1赞 Red.Wave 10/27/2023
C 还是 C++?后者不鼓励对完全相同类型的问题使用宏。正确的答案取决于语言。
1赞 Andrew Henle 10/27/2023
@YSC 这不是 OP 代码中的错别字。问题是问为什么从其他地方复制的蹩脚代码会产生发布的结果。不过,可能有很多被欺骗的候选人。
4赞 molbdnilo 10/27/2023
手动展开宏,看看代码的真实外观。(不要被如何扩展到一行所迷惑。swap

答:

1赞 Vlad from Moscow 10/27/2023 #1

只需展开代码中的宏,即可获得

int main() {
    int a = 3, b = 5, temp = 0;
    if ((3 + a > b ? a : b ) > b)
        temp = a;
    a = b;
    b = temp;    
    printf("%d %d", a, b);
}

由于条件运算符中的第一个表达式等于 ,则条件运算符的结果是 的值小于 。3 + a6ab

因此,if 语句的条件计算结果为逻辑 false,并且语句

temp = a;

被跳过。

因此,将等于 并且将等于 。a5b0

您需要使用括号。例如

#define big(a, b) ( ( a ) > ( b ) ? ( a ) : ( b ) )
#define swap(a, b) do { temp = ( a ); ( a ) = ( b ); ( b ) = temp; } while ( 0 )
1赞 Oka 10/27/2023 #2

gcc -E (仅预处理)呈现以下输出:

int main() {
    int a = 3, b = 5, temp = 0;
    if ((3 + a > b ? a : b) > b)
        temp = a; a = b; b = temp;;
    printf("%d %d", a, b);
}

由此我们可以看出,语句的主体仅由第一个表达式语句 () 组成,以第一个分号结尾。iftemp = a;

a = b; b = temp;;落在身体之外,被无条件执行。还要注意额外的分号。if


在宏中包含多个表达式语句的典型模式是利用 ,它将语句分组到新的块作用域,并允许使用尾部分号以保持一致。do { ... } while (0)

另一件事是积极地将宏参数(通常是整个宏)括起来,以确保运算符优先级尽可能保持一致。

请注意,依赖要定义的隐式变量是一种代码异味。更好的方法的一种可能性是传递类型。swaptemp

#include <stdio.h>
#define big(a, b) (((a) > (b)) ? (a) : (b))
#define swap(type, a, b) do { type temp = (a); (a) = (b); (b) = temp; } while (0)

int main(void)
{
    int a = 3, b = 5;

    if ((3 + big(a, b)) > b)
        swap(int, a, b);

    printf("%d %d\n", a, b);
}

预处理器输出:

int main(void)
{
    int a = 3, b = 5;

    if ((3 + (((a) > (b)) ? (a) : (b))) > b)
        do { int temp = (a); (a) = (b); (b) = temp; } while (0);

    printf("%d %d\n", a, b);
}

程序输出:

5 3

此示例未解决的一个问题是,这两个宏都不止一次地评估它们的论点,当涉及副作用时,这变得很棘手(例如,)。macro(func(x++), y--)

Смотритетакже: GCC CPP - 3.10.4 副作用的重复

评论

1赞 Andrew Henle 10/28/2023
C23 的 typeof 在更简单的宏中很有用。(或者它会是 C24......swap()