Featured image of post 操作符的运算顺序和优先级之间的关系

操作符的运算顺序和优先级之间的关系

很多人都有一个误区:「优先级决定了运算顺序」。然而事实并非如此,本文旨在阐明两者的关系。

许多教材里都没有将这点讲明白:「优先级和运算顺序虽然相关,但并不是谁优先级最高,一定先算谁。

本文以 C 语言为例。简单阐明一下两者究竟是什么关系。

#include <stdio.h>

int main() {
    int a = 1;
    int b = 2;
    int c = 10;
    int d = 100;
    int result = a + b + c * d; // result: 1003
    return 0;
}

很简单一个程序,然而 a + b + c * d 是如何运算的呢?或者简化一点,谁最先运算

不妨查看汇编码:

project`main:
    0x100003f70 <+0>:  pushq  %rbp 
    0x100003f71 <+1>:  movq   %rsp, %rbp
    0x100003f74 <+4>:  xorl   %eax, %eax
    0x100003f76 <+6>:  movl   $0x0, -0x4(%rbp)
    0x100003f7d <+13>: movl   $0x1, -0x8(%rbp)   // int a = 1
    0x100003f84 <+20>: movl   $0x2, -0xc(%rbp)   // int b = 2
    0x100003f8b <+27>: movl   $0xa, -0x10(%rbp)  // int c = 10
    0x100003f92 <+34>: movl   $0x64, -0x14(%rbp) // int d = 100
    0x100003f99 <+41>: movl   -0x8(%rbp), %ecx   // 将 a 的值寄存到 ECX
    0x100003f9c <+44>: addl   -0xc(%rbp), %ecx   // ECX += a
    0x100003f9f <+47>: movl   -0x10(%rbp), %edx  // 将 c 的值寄存到 EDX
    0x100003fa2 <+50>: imull  -0x14(%rbp), %edx  // EDX *= d
    0x100003fa6 <+54>: addl   %edx, %ecx         // ECX += EDX
    0x100003fa8 <+56>: movl   %ecx, -0x18(%rbp)  // result = ECX
    0x100003fab <+59>: popq   %rbp
    0x100003fac <+60>: retq   

不难发现,最先执行的居然是 a+b. 这是为何?乘法操作难道不比加法操作优先级更高吗?

的确如此1

C Operator Precedence

诚然,* 的优先级比 + 高。然而这并不代表,* 一定在 + 之前运算。

这很反直觉对不对?然而无论是先运行 a+b 或是 c*d 对于结果,都是没有影响的。算出来是一样的。

优先级可以这么理解:它决定了该操作在语法树中的层级。

一个不太标准的句法树 a + b + c * d

只要层级不乱,先算哪个,全凭编译器的喜好。可以确定,至少 gcc 编译器喜欢先算从左到右,先算 a+b


  1. C Operator Precedence↩︎

comments powered by Disqus