目录
1.表达式1
a * b + c * d + e * f;
表达式的求值部分又操作符的优先级和结合性决定。但是并不能完全决定计算顺序,这会根据编译器的不同而体现不同的计算顺序;
表达式1中,在计算的时候,由于乘法*的优先级高于加法,只能保证相邻情况下,*的计算比+的计算更早,如:并不能决定表达式中的第三个乘号*比第一个加号+更早执行。
所以表达式的计算顺序可能会分为两种。
第一种 | 第二种 | ||
第1步 | a*b | 第1步 | a*b |
2 | c*d | 2 | c*d |
3 | a*b+c*d | 3 | e*f |
4 | e*f | 4 | a*b+c*d |
5 | a*b+c*d+e*f | 5 | a*b+c*d+e*f |
有人可能会想,虽然计算顺序不同,但是结果是一样的。那么这个表达式到底有没有问题呢?
其实是有的。如果表达式中的abcdef不单纯是变量,也是表达式的话。不同的计算顺序就会对abcdef的值造成影响,而导致不同的结果。
2.表达式2
c + --c;
同理,--的优先级高于+只能决定--操作符在+的前面计算,但是我们并没有办法知道+操作符的左操作数的获取是在右操作数进行--之前还是之后;
假设c的值是4
第一种情况:左边的c是在右边的c自减之前就已经准备好了,那么结果就是4+3;
第二种情况:左边的c是在右边的c自减之后才准备好,那么结果就是3+3;
所以这个表达式仍然是有问题的,会造成歧义;
3.表达式3
#include<stdio.h>
int main()
{
int i = 10;
i = i-- - --i * (i = -3) * i++ + ++i;
printf("%d\n",i);
return 0;
}
经过上面两个表达式的讲解,我们可能已经无法明确知道这个表达式结果是什么了 。
事实也是如此,不同的编译器得到的结果也是不同的。
这道题出自《C和指针》;
值 | 编译器 |
-128 | Tandy 6000 Xenix 3.2 |
-95 | Think C 5.02(Macintosh) |
-86 | IBM PowerPC AIX 3.2.5 |
-85 | Sun Sparc cc(K&C编译器) |
-63 | gcc,HP_UX9.0,Power C 2.0.0 |
4 | Sun Sparc acc(K&C编译器) |
21 | Turbo C/C++4.5 |
22 | FreeBSD 2.1 R |
30 | Dec Alpha OSF12.0 |
36 | Dec VAX/VMS |
42 | Microsoft C 5.1 |
有兴趣的读者,可以自行了解是什么运算顺序导致这些结果。
4.表达式4
#include<stdio.h>
int fun()
{
static int count = 1;
return ++count;
}
int main()
{
int answer;
answer = fun() - fun() * fun();
printf("%d\n",answer);
return 0;
}
这个代码有没有问题呢?
实际上是有问题的
虽然大部分编译器上求的结果都是相同的;但是上述代码answer = fun() - fun() * fun();中我们只能通过操作符的优先级得知:先计算乘法再计算加法;但是我们函数的调用先后顺序是不能用操作符的优先级决定的;
在vs2022上,我经过测试得到的结果是-10,那么这个结果是怎么得到的呢?
就只能是 2 - 3 * 4;先调用第一个fun()再第二个fun()然后第三个fun(),最后再加减;
但是也有可能是4 - 2 * 3;得到-2的结果;
5.表达式5
#include<stdio.h>
int main()
{
int i = 1;
int ret = (++i) + (++i) + (++i);
printf("%d\n",ret);
printf("%d\n",i);
return 0;
}
在屏幕上会打印什么??
经过上次++,毫无疑问i的值肯定是4;
而在linux 环境gcc编译器,和vs2022上ret的结果分别是10和12;
这两种情况可能是3+3+4和4+4+4导致的;这是因为在执行第一个+号的时候第三++是否执行;仅凭借操作符的优先级和结合性是无法判断的;也就无法决定第一个+和第三个前置++的向后顺序。