C 如果执行下面的代码,输出将为8;不过,我觉得应该是10。有人能解释一下这里发生了什么吗?

C 如果执行下面的代码,输出将为8;不过,我觉得应该是10。有人能解释一下这里发生了什么吗?,c,c-preprocessor,C,C Preprocessor,为什么这个输出是8,不是应该是10 #include <stdio.h> #define A 2 + 3 #define B 2 int main() { printf("Hello, World!\n"); printf("%d\n", A * B); return 0; } #包括 #定义2+3 #定义b2 int main() { printf(“你好,世界!\n”); printf(“%d\n”,A*B); 返回0; } #define预处理器指

为什么这个输出是8,不是应该是10

#include <stdio.h>
#define A 2 + 3
#define B 2 

int main()
{
    printf("Hello, World!\n");
    printf("%d\n", A * B);
    return 0;
}
#包括
#定义2+3
#定义b2
int main()
{
printf(“你好,世界!\n”);
printf(“%d\n”,A*B);
返回0;
}
#define
预处理器指令只是文本替换
A
B
不是变量,因此您的
printf
变成

printf("%d\n", 2 + 3 * 2);
也就是8,2*3等于6,加上2等于8

要解决此问题并获得
10
,请在指令周围放置
()

#define A (2 + 3)
#define B 2
这将导致您的
printf
扩展到

printf("%d\n", (2 + 3) * 2);
要查看预处理器在编译之前是如何展开的,可以将
-E
标志传递给
gcc
clang

但是,更好的解决方案是对这些常量使用
const int
enum

const int A = 2 + 3;
const int B = 2;

// or
enum { A = 2 + 3, B = 2 };
#define
预处理器指令只是文本替换
A
B
不是变量,因此您的
printf
变成

printf("%d\n", 2 + 3 * 2);
也就是8,2*3等于6,加上2等于8

要解决此问题并获得
10
,请在指令周围放置
()

#define A (2 + 3)
#define B 2
这将导致您的
printf
扩展到

printf("%d\n", (2 + 3) * 2);
要查看预处理器在编译之前是如何展开的,可以将
-E
标志传递给
gcc
clang

但是,更好的解决方案是对这些常量使用
const int
enum

const int A = 2 + 3;
const int B = 2;

// or
enum { A = 2 + 3, B = 2 };

这就是为什么宏中的括号很重要

宏执行简单的文本替换。因此,在宏处理之后,您的代码如下所示:

int main()
{
    printf("Hello, World!\n");
    printf("%d\n", 3 + 9 * 2);
    return 0;
}
因为乘法具有更高的优先级,所以乘法首先发生,因此结果为21

通过在宏中插入括号,可以减少惊喜:

#define A (3 + 9)
#define B (2)
这导致:

int main()
{
    printf("Hello, World!\n");
    printf("%d\n", (3 + 9) * (2));
    return 0;
}

这将输出24。

这就是为什么宏中的括号很重要

宏执行简单的文本替换。因此,在宏处理之后,您的代码如下所示:

int main()
{
    printf("Hello, World!\n");
    printf("%d\n", 3 + 9 * 2);
    return 0;
}
因为乘法具有更高的优先级,所以乘法首先发生,因此结果为21

通过在宏中插入括号,可以减少惊喜:

#define A (3 + 9)
#define B (2)
这导致:

int main()
{
    printf("Hello, World!\n");
    printf("%d\n", (3 + 9) * (2));
    return 0;
}

这将输出24。

按照它执行的顺序,您正在执行9*2+3。我不确定你是如何得到这些数字的,因为它应该是21。

按照它执行的顺序,你的是9*2+3。我不确定你是如何得到这些数字的,因为它应该是21。

宏扩展为
printf(“%d\n”,3+9*2)宏扩展为
printf(“%d\n”,3+9*2)宏扩展发生在预处理的第四阶段中:

  • 执行预处理指令,宏调用展开,,并执行_Pragma一元运算符表达式。(…)
  • 因此,每个宏将精确地扩展到其定义
    A
    ->
    3+9
    B
    ->
    2

    结果
    printf(“%d\n”,3+9*2)

    现在,编译器的角色是从语法和语义上分析表达式,在编译期间,基于C语言的优先运算符,它的计算值可能会达到21

    movl    $.LC1, %edi //first argument of printf "%d\n"
    movl    $0, %eax    // second argument of printf 21
    call    printf
    

    宏扩展发生在预处理的第四阶段:

  • 执行预处理指令,宏调用展开,,并执行_Pragma一元运算符表达式。(…)
  • 因此,每个宏将精确地扩展到其定义
    A
    ->
    3+9
    B
    ->
    2

    结果
    printf(“%d\n”,3+9*2)

    现在,编译器的角色是从语法和语义上分析表达式,在编译期间,基于C语言的优先运算符,它的计算值可能会达到21

    movl    $.LC1, %edi //first argument of printf "%d\n"
    movl    $0, %eax    // second argument of printf 21
    call    printf
    

    你知道宏是如何扩展的吗?如果交换
    A
    B
    ,你会感到惊讶。现在我明白了为什么在社交媒体上,他们会发布诸如“3+9*2的结果是什么?”之类的内容。所有内容都在这里:@Meninx-メネンックス 这只是对宏扩展的误解,我相信OP理解算术优先级。你知道宏是如何扩展的吗?如果交换
    a
    B
    ,你会感到惊讶……现在我明白了为什么在社交媒体上,他们会发布诸如“3+9*2的结果是什么?”之类的东西,一切都在这里:@Meninx-メネンックス 这只是对宏展开的误解,我相信OP理解算术优先。对不起,我意识到我的质疑是错误的,但我理解你的意思。Thanks@RyanHaining我的荣幸:)对不起,我意识到我问错了,但我明白你的意思。Thanks@RyanHaining我的荣幸:)