C语言优先级列表

时间:2022-12-15 08:07:49

 -初等,4个: ( ) [ ] -> 指向结构体成员 . 结构体成员 
 -单目,9个: ! ~ ++ -- -负号 (类型) *指针 &取地址 sizeof长度 
 -算术,5个: * / % + -减 
 -位移,2个: << >> 
 -关系,6个: < <= > >= == 等于 != 不等于 
 -位逻,3个: & 按位与 ^ 按位异或 | 按位或 
 -逻辑,2个: && 逻辑与 || 逻辑或 
 -条件,1个,三目: ? : 
 -赋值,11个: = += -= *= /= %= >>= <<= &= ^= |= 
 -逗号,1个: , 

结合方向自右向左的只有三类:赋值、单目和三目 
同一优先级 的运算顺序由结合方向决定

           Turbo C 运算符的优先次序 
━━━━━━━━━━━━━━━━━━━━━━━━━━━
                    表达式                              ┃优先级 
────────────────────────────╂──── 
()(小括号) [](数组下标) .(结构成员) ->(指针型结构成员)┃ 最高 
────────────────────────────┃ ↑ 
!(逻辑非) .(位取反) -(负号) ++(加1) --(减1) &(变量地址)┃ │ 
────────────────────────────┃ │ 
   *(指针所指内容) type(函数说明) sizeof(长度计算)    ┃ │ 
────────────────────────────┃ │ 
     *(乘)     /(除)     %(取模)                   ┃ │ 
────────────────────────────┃ │ 
     +(加)     -(减)                                    ┃ │ 
────────────────────────────┃ │ 
     <<(位左移)          >>(位右移)            ┃ │ 
────────────────────────────┃ │ 
     <(小于)   <=(小于等于)   >(大于)   >=(大于等于)    ┃ │ 
────────────────────────────┃ │ 
     ==(等于)       !=(不等于)                    ┃ │ 
────────────────────────────┃ │ 
     &(位与)                                            ┃ │ 
────────────────────────────┃ │ 
     ^(位异或)                                          ┃ │ 
────────────────────────────┃ │ 
     |(位或)                                            ┃ │ 
────────────────────────────┃ │ 
     &&(逻辑与)                                         ┃ │ 
────────────────────────────┃ │ 
     ||(逻辑或)                                         ┃ │ 
────────────────────────────┃ │ 
     ?:(?表达式)                                        ┃ │ 
────────────────────────────┃ │ 
     =    +=   -=(联合操作)                       ┃ │ 
────────────────────────────┃ │ 
     ,(逗号运算符)                                      ┃ 最低

-------------------------------------------------------------------------------------------------

如果一个表达式 包含两个或两个以上的运算符,那么操作数的结合方式 将决定这个表达式的结果。为了 简便,我们把包含两个或两个以上运算符的表达式称为复合表达式 。例如:

        3 + 2 * 5

如果 3 和 2 结合在一起,那么这个表达式的结果将会是 5 * 5 等于 25。当然,C 语言里,本例的 3 不会 和 2 结合,而是 2 和 5 结合,得到 3 + 10 等于 13。

    运算符的优先级 (precedence)和结合律 (associativity)决定操作数的结合方式。当复合表达式中的 运算符的优先级不同 时,操作数的结合方式由优先级 决定。当复合表达式中的运算符的优先级相同 时,操作 数的结合方式由结合律 决定。不过,我们也可以使用括号 强制把操作数结合在一起。例如:

        (3 + 2) * 5

强制把 3 和 2 结合在一起。


1. 优先级

    操作数的结合方式决定复合表达式的值。当复合表达式中的运算符的优先级不同时,操作数的结合方式 由优先级决定。操作数总是围绕优先级较高 的运算符进行结合。例如:

        8.0 + 20.0 / 4.0

因为除法运算符的优先级比加法运算符高,所以 20.0 和 4.0 结合,得到 5.0,然后 8.0 和 5.0 结合,得 到 13.0。


2. 结合律

    当复合表达式中的运算符的优先级相同时,操作数的结合方式由结合律决定。例如:

        8.0 + 20.0 / 4.0 * 2.0

乘法运算符的优先级和除法运算符相同。不过,由于它们的结合率都是从左到右 (即从左到右进行结合), 所以 20.0 和 4.0 结合;得到的结果 5.0 再和 2.0 结合,得到 10.0;8.0 和 10.0 结合,得到 18.0。

    大多数运算符的结合律都是从左到右 ,不过也有从右到左 的(例如赋值运算符)。


3. 使用括号强制结合操作数

    使用括号可以强制把操作数结合在一起。被括号括住的子表达式 会被当作一个独立的个体 进行处理,这 个个体同样要受到优先级和结合律的约束。例如:

        (8.0 + 20.0 / 4.0) * 2.0

强制把 8.0 + 20.0 / 4.0 当成一个个体来处理。因为除法运算符的优先级比加法运算符高,所以 20.0 和 4.0 结合,得到 5.0;然后 8.0 和 5.0 结合,得到 13.0;13.0 和 2.0 结合得到 26.0。

        -9 + 4 * 5 + 6 + 8 * 7 - 1

根据优先级和结合律,这个表达式的结合方式等同于:

        ( ( ( ( ( -9) ( 4 * 5) ) + 6 ) ( 8 * 7) ) - 1 )

由于赋值运算符的结合律是从右到左,所以

        i = j = k = l

的结合方式等同于:

        ( i = ( j = ( k = l) ) )

 

4. 运算顺序

    优先级和结合律仅能确定操作数的结合方式,却不能决定操作数的运算顺序 。例如:

        5 * 3 + 8 * 4

根据优先级和结合律,我们知道,这个表达式的结合方式等同于

        (5 * 3) + (8 * 4)  // 5 * 3 和 8 * 4 是 + 的操作数

但是, 到底是先运算 5 * 3 还是先运算 8 * 4,我们并不能确定。它们运算的先后是由编译器决定 的。标准不规定操作数的运算顺序是为了让特定系统的编译器选择对该系统来说效率最高的运算顺序。但无论它们的运算先后如何,最终得到的结果都是 47。

下面我们来看一个小程序。

        /*--------------------------------------------------------------
         | 作者: Antigloss @ http://stdcpp.cn @ 蚂蚁的 C/C++ 标准编程
         |  
         | 功能: 演示优先级 结合律 对运算结果的影响
          -------------------------------------------------------------*/

        #include < stdio.h>

        int main(void)
        {
            int var1, var2;

            var1 = var2 = -(9 + 4) * 5 + (6 + 8 * (7 - 1));
            printf("var1 = var2 = %d/n", var1);

            return 0;
        }

请认真阅读以上程序,想想会出现什么结果,然后编译运行,看看运行结果和您想象的是否一样。

    因为优先级和结合律不能决定操作数的运算顺序 , 所以我们不知道到底是先运算 -(9 + 4) * 5 还是先运算 (6 + 8 * (7 - 1))。它们运算的先后是由编译器决定的。假设先运算 -(9 + 4) * 5,虽然加法运算符的优先级较低,但是括号强制把 9 和 4 结合在一起,得到 13。负号运算符的优先级比乘法运算符高,其作用于 13 得 -13。于是我们得到:

        var1 = var2 = -13 * 5 + (6 + 8 * (7 - 1));

由于乘法运算符的优先级比加法运算符高,所以 -13 和 5 结合在一起,得到 -65:

        var1 = var2 = -65 + (6 + 8 * (7 - 1));

在 (6 + 8 * (7 - 1)) 中,括号强制把 7 和 1 结合,得 6:

        var1 = var2 = -65 + (6 + 8 * 6);

因为 * 优先级高于 + ,于是我们得到:

        var1 = var2 = -65 + (6 + 48);

进而

        var1 = var2 = -65 + 54;
        var1 = var2 = -11;

因为赋值运算符的结合率是从右到左 ,所以 -11 被赋值给 var2,接着 var2 被赋值给 var1。最终的结果是,var1 和 var2 相等,它们的值都是 -11。


5. 规定了操作数的运算顺序的运算符

    C 语言中,有四个运算符对其操作数的运算顺序做了明确的规定:

        &&   ||   ?:   ,

除了这四个运算符以外,其它运算符都没有规定其操作数的运算顺序。


6. C 语言提供的所有运算符

    下图列出了 C 语言提供的所有运算符,按优先级从高到低进行排列,优先级相同的运算符放在同一行。