社区
C语言
帖子详情
i + i++ ;是undefined behavior的表达式语句吗?理由!
mu_yang
2009-08-01 07:21:38
结论无关紧要,
核心是理由。
...全文
872
121
打赏
收藏
i + i++ ;是undefined behavior的表达式语句吗?理由!
结论无关紧要, 核心是理由。
复制链接
扫一扫
分享
举报
写回复
配置赞助广告
用AI写文章
121 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
taodm
2009-08-03
打赏
举报
回复
囧,讲C、C++标准不完善的书已经够多了,就别再扯远了。
mu_yang
2009-08-03
打赏
举报
回复
都快搞成哲学问题了
呵
1.“完善”的定义?
2.我们现在讨论问题只能是在标准的框架之下
3.标准有错误或不合理或不合逻辑不是绝对不可能的,但一定要有根据的说
泛泛地谈标准的完善与不完善,没有意义
飞天御剑流
2009-08-03
打赏
举报
回复
标准不是不能完善,而是不可能完善,或者说不可能绝对完善,无论计算机语言标准也好,现实中的法律也好,都不可能有绝对完善。
我们这个宇宙是相对的,不是绝对的,完善这个词是相对的,当我们说一个东西是否完善的时候,只是相对于某个参照物而言,而参照物可以有无限多个.........
说白了,就是我们可以要求保准在某方面做得完善,但不可能要求它方方面面都做得完善。
qepjatdwj
2009-08-02
打赏
举报
回复
原来C这么博大精深!
mu_yang
2009-08-02
打赏
举报
回复
我很欣赏#24楼认真明晰概念的这种态度
也感谢#24对unspecified behavior、
implemantation defined、
undefined behavior
这三个概念的阐述
我很想问继续请教
既然unspecified behavior“意思是标准提出两种或多种处理方法,编译器可以从中选择一种”
那么您认为标准对 i + i++ ; 提出了哪些处理方法?
mu_yang
2009-08-02
打赏
举报
回复
[Quote=引用 65 楼 baihacker 的回复:]
命令式,函数式,逻辑式,脚本式.
几种并不是独立的,前三种是从本身范式来看的,脚本是从应用角度来看的.
而且,在函数式中也可以有命令式,在命令式中也可以有函数式.
[/Quote]
多谢指教
以后再仔细研究
baihacker
2009-08-02
打赏
举报
回复
命令式,函数式,逻辑式,脚本式.
几种并不是独立的,前三种是从本身范式来看的,脚本是从应用角度来看的.
而且,在函数式中也可以有命令式,在命令式中也可以有函数式.
baihacker
2009-08-02
打赏
举报
回复
...我是在和中缀类比...
把()里面的内容看作运算符,把函数名看作操作数,就是后缀式,
把函数名看作运算符,把()里面的看作操作数,就是前缀式了.
从描述这个表达式的意思来讲,两者没有本质区别,因为可以都归为后缀表达式,何必再多事.
mu_yang
2009-08-02
打赏
举报
回复
[Quote=引用 52 楼 baihacker 的回复:]
问题的源头在命令式语言:用变量暂时保存一个状态,所以就有了这种副作用.
[/Quote]
不太理解
能否详细说说
除了“命令式语言”
还有什么“式”?
mu_yang
2009-08-02
打赏
举报
回复
[Quote=引用 61 楼 baihacker 的回复:]
中缀,因为这个运算符在两个操作数中间...
+ a b 前
a + b 中
a b + 后
a ? b : c 中
更多操作数的运算,比如是X个操作数的,那么用中缀就要用X-1个符号,很不方便,也不直观,于是就用前缀式:
function(a,b,c,d,e);
函数调用,可以看作一种前缀式.
[/Quote]
我的印象
C语言恰恰把函数调用归为了Postfix operators
baihacker
2009-08-02
打赏
举报
回复
中缀,因为这个运算符在两个操作数中间...
+ a b 前
a + b 中
a b + 后
a ? b : c 中
更多操作数的运算,比如是X个操作数的,那么用中缀就要用X-1个符号,很不方便,也不直观,于是就用前缀式:
function(a,b,c,d,e);
函数调用,可以看作一种前缀式.
mu_yang
2009-08-02
打赏
举报
回复
[Quote=引用 58 楼 baihacker 的回复:]
写成a+b的形式的时候已经是中缀了.
在C中是有初等表达式,后缀表达式的..
然后中缀表达式由于优先级的原因,被分为
乘法性质表达式,加法性质表达式,位移性质表达式,关系性质表达式,等价性质表达式,and,xor,or...一大堆
这样是有利于语法的形式化的.
[/Quote]
那“逗号”是什么缀?
mu_yang
2009-08-02
打赏
举报
回复
[Quote=引用 45 楼 arong1234 的回复:]
……但是意义在哪,谁也不知道。
……
[/Quote]
你不知道
不能说“谁也不知道”
麻烦不知道这问题意义的网友
先正式指出自己不知道
麻烦认为该问题“无意义”的网友
给出象样的、值得反驳或商榷的理由
或者另外发帖讨论
在下一定参加
飞天御剑流
2009-08-02
打赏
举报
回复
i + i++ ;是undefined behavior的表达式语句吗?理由!
--------------------------------------------------------
单看楼主这句话,楼主就有一个概念上的错误。
求值顺序不是undefined behavior,而是unspecified,unspecified跟undefined是两码事。
在标准中,有三种行为方式的规定:
一:unspecified behavior,未指定行为。意思是标准提出两种或多种处理方法,编译器可以从中选择一种;
二:implemantation defined,实现定义行为。基本意思跟unspecified一样,也是编译器从中选择一种,但是,编译器需要在说明文档中指出此编译器采用了哪一种方法,而unspecified不需要告诉使用者。
三:就是undefined behavior了,未定义行为。意思是标准对于此施加于错误的程序结构或者错误数据上的行为,不作任何规定。编译器可以自行处理。
上述三种行为标准在前部的概念解释中都有介绍,限于编幅不在这里摘录了,可以自行查阅。
求值顺序属于unspeciafied行为,不是undefined行为。编译器对于运算符的左或右操作数,可以选择其中一种计算顺序,并且不需要在文档中说明。
这个问题楼主既然发在c版,就应该用c标准去解释。摘录c99的原文,c90基本一样。
Except as specified later (for the function-call (), &&, ||, ?:, and comma operators), the order of evaluation of subexpressions and the order in which side effects take place are both unspecified.
就是除了函数调用、逻辑与和或、条件表达式、逗号表达式外,其它表达式的计算顺序与副作用的产生都是未指定的。
根据这条规定,i + i++;就是未指定行为。对于i与i++的计算顺序,不同编译器会有所不同。
还需要注意,对于副作用何时产生,标准只保证在达到顺序点时,副作用被完全求值,但不保证达到顺序点前,副作用何时被求值。
正因为如此,在楼主贴出来的这种表达式里,别以为那个是后增量,就必定会先使用后一个i,再自加,不一定的!!此表达式语句的分号处有一个顺序点,只保证在达到此顺序点时i自加一次,但何时i进行自加,各个编译器会有所不同,也因此各种编译器可能呈现不同的结果。
特别指出的是,由于国内很多书(也包括国外有些书),并没有对求值顺序与结合性作一个完整的表述,造成不少人在这些问题上互相混淆,特别是那些基础不牢的人,容易把求值顺序、优先级、结合性几个概念理解得一蹋糊涂!
baihacker
2009-08-02
打赏
举报
回复
写成a+b的形式的时候已经是中缀了.
在C中是有初等表达式,后缀表达式的..
然后中缀表达式由于优先级的原因,被分为
乘法性质表达式,加法性质表达式,位移性质表达式,关系性质表达式,等价性质表达式,and,xor,or...一大堆
这样是有利于语法的形式化的.
mu_yang
2009-08-02
打赏
举报
回复
[Quote=引用 51 楼 arong1234 的回复:]
其实无论是楼主还是热心回答问题的大众,只要能说出“回答好这个问题后的好处在哪”,就一切ok了。
[/Quote]
我来论坛是为了讨论问题的
不是来向小学生传教的
当然有初学者有疑惑需要帮助的时候是另一回事情
mu_yang
2009-08-02
打赏
举报
回复
[Quote=引用 49 楼 baihacker 的回复:]
一个是单目运算符,另一个是双目的...
由于中缀的表达式形式在有若干个双目运算符的时候,先计算哪个是不确定的,所以在不同的运算符中出现了优先级,在相同的运算符中出现了结合性,以便于确定计算顺序.
在单目运算中也有,不过单目是针对一个操作数的,
后缀的单目运算高于前缀式的:如*p++;
在两个前缀的时候离表达式近的先:如*++p;
在两个后缀的时候也是离表达式近的先:如p++[1],pp[1][2];
i + i++;
中+是双目的
++是单目的
++和+木有竞争关系
而a + b * c;
这两个双目会有竞争关系的.
[/Quote]
几乎完全不能同意
不过话题可能越扯越远了
我就不多说了
只讲一句
“中缀”不是C的概念
我倾向于只用C的概念讨论C
mu_yang
2009-08-02
打赏
举报
回复
[Quote=引用 50 楼 arong1234 的回复:]
我所谓的二义性,是指那种只要
一看就知道它肯定不可能产生二义性的直观二义性
,
[/Quote]
呵呵
压根不需要对语言的理解
只需要“一看”
佩服
happypeter2008
2009-08-02
打赏
举报
回复
[Quote=引用 50 楼 arong1234 的回复:]
我所谓的二义性,是指那种只要一看就知道它肯定不可能产生二义性的直观二义性,而不是你这种通过“专家”证明它没有二义性的东西。绝大多数C++程序员恐怕都不会研究这么深入,能够引经据典来证明一个东西,在这种情况下,你这种需要证明的二义性只能让那些不知道的人吃苦。而从上面那位盛赞“C博大精深”的人来看,还是有很多人被你引导到以为这很重要的方向去的。
其实很简单
a=i + i++;
和
a= i + i;
i++
这两种表达式谁更没有让人糊涂的东西,不是非常一目了然么?有什么理由我们应该去研究前者而不使用后者。
引用 48 楼 mu_yang 的回复:
引用 43 楼 arong1234 的回复:
写软件的正确方法是使用最简单的没有二义性的且容易阅读、维护的表达式,从而降低成本。即使有人证明这个表达式是安全的,你能在哪儿用?项目组中只要有一个对此有疑问,你的表达式都会产生非常不好的后果。
“写软件的正确方法是使用最简单的没有二义性的且容易阅读、维护的表达式”
这很对
但前提是知道什么样的有“二义性”、什么样的没有“二义性”
难道不是吗
[/Quote]
同意
mu_yang
2009-08-02
打赏
举报
回复
[Quote=引用 45 楼 arong1234 的回复:]
只要你能证明这种问题的实际意义,我相信谁也不能指责你无聊或者无知。关键研究这个问题的人从来不正面证明自己的研究的意义何在,顶多说这是“C++知识”,弄清楚有意义,但是意义在哪,谁也不知道。
引用 42 楼 mu_yang 的回复:
引用 38 楼 arong1234 的回复:
什么时候大家才能摆脱“不管它有没有用,只要是‘知识’我就要研究”和“有麻烦解决麻烦,没有麻烦制造麻烦我也要解决”的怪圈有多好?研究这种无聊幼稚的问题,除了耽误时间,实在想不出有什么用处。
恐怕是狂了一点
不能说你不理解问题的意义
就都是“幼稚无聊”
而你知道的问题才不是“幼稚无聊”吧
[/Quote]
相信有识之士能理解这问题的意义
至于我提出它
自然是认为有意义
但我没有义务向不知道问题意义的人科普
至于你说没意义或你认为没意义
我没看到你拿出了象样的理由
加载更多回复(101)
C/C
++
中的未定义行为和`sequence points`, `sequenced`,`unsequenced`
C/C
++
语言中的未定义行为和通过sequence point帮助判断避免。 gcc针对这种情况不会给出警告,天坑,肉眼debug完全没门。
C语言入门:从Hello World到指针与内存管理的核心概念解析
编程语言是计算机科学的基础工具,其核心在于将人类逻辑转化为机器可执行的指令。C语言作为一门接近底层的系统编程语言,其设计哲学直接映射了计算机的硬件架构和工作原理。通过学习C语言,开发者能够深入理解程序在内存中的存储方式、CPU的指令执行流程以及操作系统与应用程序的交互机制,这种底层认知是构建高效、可靠软件系统的技术基石。在工程实践中,掌握变量与数据类型、控制流程、函数模块化等基础概念,特别是理解指针与内存管理的本质,是进行系统编程、嵌入式开发和性能优化的关键。本文以C语言入门为切入点,系统讲解从程序结构、编
C
++
运算符陷阱全解析:从优先级到重载的避坑指南
在C
++
编程中,运算符是构建
表达式
的基础,其优先级、结合性和隐式类型转换等特性直接影响代码的执行逻辑与安全性。理解运算符的求值顺序和类型提升规则,是避免未定义行为和逻辑错误的关键。例如,位运算符与关系运算符混用时的优先级陷阱,以及自增自减运算符在序列点中的未定义行为,都是实际开发中高频出现的‘坑’。这些原理不仅关系到代码的正确性,也影响程序的性能与可维护性。在系统编程、嵌入式开发和高性能计算等场景中,正确使用运算符能提升代码健壮性。本文聚焦于C
++
运算符的常见问题,深入剖析优先级、结合性、自增自减的微妙差异
C
++
vector遍历全解析:从性能优化到现代语法实践
在C
++
编程中,容器遍历是基础且高频的操作,其核心在于如何高效、安全地访问序列化数据。从原理上看,遍历本质是通过迭代器或指针顺序访问连续内存区域,这直接关系到缓存局部性和指令级优化。在技术价值层面,不同的遍历方式不仅影响代码可读性和安全性,更在性能关键场景下产生显著差异,例如在游戏引擎或高频交易系统中,微小的开销累积可能导致整体性能瓶颈。应用场景涵盖从简单的数据打印到复杂的并行计算,其中迭代器失效和边界检查是常见陷阱。本文聚焦std::vector这一最常用的序列容器,深入对比下标访问、迭代器、基于范围的f
Webots 高级渲染示例深度解析:PBRAppearance、Skin 动画与环境光遮蔽(Ambient Occlusion)
本文基于 Webots 官方示例仓库中的 [docs/guide/samples-rendering.md](https://link.gitcode.com/i/59d56506f7371713747d2e4282ff7520) 指南,深入讲解 Webots 的三大高级 3D 渲染示例世界:`animated_skin.wbt`、`physically_based_rendering.wbt`
C语言
70,040
社区成员
243,237
社区内容
发帖
与我相关
我的任务
C语言
C语言相关问题讨论
复制链接
扫一扫
分享
社区描述
C语言相关问题讨论
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章