24. +、-、*、/、= 的优先级
1. 优先级 和数学一样,C 语言规定先乘除后加减。也就是说,乘法运算符和除法运算符的优先级(Precedence)比加法运算符和减法运算符高。同时,C 语言也规定,如果两个运算符的优先级相同,并且它们之间没有被优先级比它们高或者低的运算符隔开,则它们的运算顺序根据它们在语句中出现的先后而定。大多数运算符都是从左向右进行运算的,不过也有从右向左进行运算的(例如赋值运算符)。乘法运算符和除法运算符的优先级相同,加法运算符和减法运算符的优先级相同。因此,以下语句 var = 8.0 + 20.0 / 4.0 * 2.0; 运算顺序为: 20.0 / 4.0 在这个表达式中,/ 和 * 优先级相同,而且是从左向右进行运算的,所以先运算 20.0 / 4.0,然后才轮到 5.0 * 2.0。 如果我们想让加法先进行,可以给 8.0 + 20.0 加上括号: var = (8.0 + 20.0) / 4.0 * 2.0; 这个语句的运算顺序为: 8.0 + 20.0 C 语言规定,先进行括号里面的运算,后进行括号外面的运算。在括号里面,运算顺序和上面讨论的一样。例如: var = (8.0 + 20.0 / 4.0 * 2.0) / 3.0; 运算顺序为: 20.0 / 4.0 下表总结了这几个运算符的优先级以及它们的结合律,按优先级从高到低进行排列 运算符 结合律 () 从左向右
运算符优先级(Operator precedence)是决定运算顺序的重要规则,但不能完全(也没必要完全)确定运算顺序。例如: 5 * 3 + 8 * 4; 根据运算符优先级,我们知道,乘法运算先于加法运算。但是 5 * 3 和 8 * 4 谁先谁后,我们并不能确定。它们运算的先后是由编译器决定的。这是因为某种运算顺序在某种系统中效率更高,而另一种运算顺序在另一种系统中效率更高。无论它们的运算先后如何,最终得到的结果都是 47。 您可能会说:“乘法不是从左向右进行运算的吗?这不是说明最左边的乘法最先进行吗?”是的,乘法的确是从左向右进行运算,但是您也要看到,这两个乘法运算符之间被加法运算符隔开了!我们举一个例子来说明乘法从左向右进行运算的意思。以下语句 5 * 2 * 9 * 4; 运算顺序为: 5 * 2
/* precedence.c -- 优先级测试 */ int main(void) var1 = var2 = -(9 + 4) * 5 + (6 + 8 * (7 - 1)); return 0; 请认真阅读以上程序,想想会出现什么结果,然后编译运行,看看运行结果和您想象的是否一样。 首先,括号运算符优先级最高。但是 (9 + 4) 和 (6 + 8 * (7 - 1)) 运算的先后是由编译器决定的。假设 (9 + 4) 先进行,则运算后得 13,然后负号运算符作用于 13 得 -13。于是我们得到: var1 = var2 = -13 * 5 + (6 + 8 * (7 - 1)); 在 (6 + 8 * (7 - 1)) 中,先运算 (7 - 1),得: var1 = var2 = -13 * 5 + (6 + 8 * 6); 因为 * 优先级高于 +,于是我们得到: var1 = var2 = -13 * 5 + (6 + 48); 进而 var1 = var2 = -13 * 5 + 54; 因为赋值运算是从右向左的,所以 -11 被赋值给 var2,接着 var2 被赋值给 var1。最终的结果是,var1 和 var2 相等,它们的值都是 -11。 |
25. 模除运算符 % | |||
% 是模除运算符(Modulus Operator),用于求余数。% 只可用于对整数进行模除,不可用于浮点数。例如: 15 % 2 // 正确。余数为 1 C99 以前,并没有规定如果操作数中有负数,模除的结果会是什么。C99 规定,如果 % 左边的操作数是正数,模除的结果也是正数;如果 % 左边的操作数是负数,模除的结果就是负数。例如: 15 % 2 // 余 1 标准规定,如果 a 和 b 都是整数,则 a % b 可以用公式 a - (a / b) * b 算出。例如: -15 % 2 == -15 - (-15 / 2) * 2 == -15 - (-7) * 2 == -1 最后,我们看一个小程序。 /* months_to_year.c -- 将用户输入的月数转换成年数和月数 */ #include <stdio.h> printf("Enter the number of months: "); years = months / months_per_year; /* 算出年数 */ printf("%d months is %d years, %d months.\n", months, years, months_left); return 0;
|