首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C语言前缀后缀问题

C语言前缀后缀问题
EN

Stack Overflow用户
提问于 2014-04-12 13:02:29
回答 1查看 630关注 0票数 0

我已经用c写了下面的代码。

代码语言:javascript
复制
int x = 8;
x -= --x - x--;
printf("%d", x);

它正在打印6,但根据我的逻辑语句应该转换为(从右到左执行)

代码语言:javascript
复制
x = 6-6-8; 

所以答案应该是-8。

有人能说出这里发生了什么吗?

EN

回答 1

Stack Overflow用户

发布于 2014-04-12 13:05:47

这是一种未定义的行为。C99标准§6.5µ2表示

在前一个序列点和下一个序列点之间,对象的存储值最多只能通过表达式的求值修改一次。此外,应只读取先验值,以确定要存储的值。

代码语言:javascript
复制
x -= --x - x--;

// equivalent to
x = x - --x - x--;

// postfix decrement has higher precedence than
// prefix decrement. Both have higher precedence than
// subtraction operator. Therefore the above statement is
// equivalent to
x = x - (--x) - (x--);

// the subtraction associates from left to right 
// therefore the above statement is parsed as
x = (x - (--x)) - (x--);

现在,这里需要注意的重要一点是,-运算符的操作数的求值是相对于彼此的无序的。这意味着不确定首先计算哪个子表达式(x - (--x))(x--)

引用来自cppreference.com的这篇优秀文章Order of evaluation -

在C中没有从左到右或从右到左计算的概念,这与运算符的从左到右和从右到左的关联性相混淆:由于operator+的从左到右的关联性,表达式a+b+c被解析为(a + b) + C,但是子表达式c可能在运行时首先(或最后,或同时作为a或b)进行计算。

需要注意的第二件重要事情是,在上面的语句中,由于表达式--xx--的副作用,x的值被修改了两次。在这两个表达式的求值之间没有序列点,因此不能保证何时会发生副作用。因此,从标准中参考上述部分,它是未定义的行为。

结合上述两点,表达式可以计算为多个值。

代码语言:javascript
复制
int x = 8;
x = (x - (--x)) - (x--);
//  (a)   (b)      (c)   name of the sub expressions

// assume (c) is evaluated first and side effect
// takes place immediately. Then (b) is evaluated and
// side effect takes place immediately

x = (6 - (6)) - (8);   // -8

// assume (a) is evaluated first, then (b)
// however the side effect of (b) does not take
// place before (c) gets evaluated          

x = (8 - (7)) - (7);   // -6      

这只是两个示例,用来说明语句执行后x可以具有的不同值。这并不意味着x将始终具有所有可能值中的一个值。标准说它是未定义的行为,这意味着该行为是不可预测的。该标准对处理此类情况的实现没有任何要求。未定义的行为意味着任何事情都可能发生,从守护进程飞出你的鼻子到你的硬盘被格式化。您应该始终避免编写调用未定义行为的代码。有关更多详细信息,请阅读此- Undefined Behavior and Sequence Points

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23026294

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档