C语言的未定义行为

下面的两篇关于“C语言的未定义行为”的文章均摘自其他博客,在此表示感谢!

 

第一篇:

int a=5,b;

b=++a*–a;

b的值是多少呢。。

这是C语言的未定义行为,C标准没有对其进行定义,编译器可以随意进行计算

随后测试vc6的种种行为

//总结:

//a=5;

//b=++a*++a;    49

//b=a++*++a;    36

//b=++a*a++;    36

//b=a++*a++;    25

3.2 使用我的编译器,下面的代码int i=7; printf(“%dn”, i++ *

i++); 返回49?不管按什么顺序计算, 难道不该打印出56吗?

尽管后缀自加和后缀自减操作符++ 和– 在输出其旧值之后才会执行运算,

但这里的“之后”常常被误解。没有任何保证确保自增或自减会在输出变量原值之

后和对表达式的其它部分进行计算之前立即进行。也不能保证变量的更新会在表

达式“完成” (按照ANSI C 的术语, 在下一个“序列点” 之前, 参见问题3.7) 之前

的某个时刻进行。本例中, 编译器选择使用变量的旧值相乘以后再对二者进行自

增运算。

包含多个不确定的副作用的代码的行为总是被认为未定义。(简单而言, “多

个不确定副作用” 是指在同一个表达式中使用导致同一对象修改两次或修改以后

又被引用的自增, 自减和赋值操作符的任何组合。这是一个粗略的定义; 严格的定

义参见问题3.7, “未定义” 的含义参见问题11.32。) 甚至都不要试图探究这些东

西在你的编译器中是如何实现的(这与许多C 教科书上的弱智练习正好相反); 正

如K&R 明智地指出, “如果你不知道它们在不同的机器上如何实现, 这样的无知可

能恰恰会有助于保护你。”

 

第二篇:

未定义(undefined)行为,也就是说,C++标准没有定义这种行为。

 

C++Primer第四版中的解释:

          使用了未定义行为的程序都是错误的,即使程序能够运行,也只是巧合。未定义行为源于编译器不能检测到的程序错误或太麻烦以至无法检测的错误。

          不幸的是,含有未定义行为的程序在有些环境或编译器中可以正确执行,但并不能保证同一程序在不同编译器中甚至在当前编译器的后继版本中会继续正确运行,也不能保证程序在一组输入上可以正确运行且在另一组输入上也能正确运行。

          程序不应该依赖未定义行为。

          同样地,通常程序不应该依赖机器相关的行为,比如假定int的位数是个固定且已知的值。我们称这样的程序是不可移植的(nonportable)。当程序移植到另外一台机器上时,要寻找并更改任何依赖机器相关操作的代码。在本来可以运行的程序中寻找这类问题是一项非常不愉快的任务。

 

 

下面是摘自网上的关于未定义行为的介绍:

数学概念上来讲,现代计算机就是“万能图灵机”的一个具体实现。从哲学上来说,以二进制逻辑运算为基础的计算机,其行为必然是确定的。“对于一个确定的输入,其输出是完全确定的。”哲学家和科幻小说作家们统一的观点是:无论如何,如果不为计算机的基础计算模型引入不确定性,人工智能(AI)不可能真正实现。但是,向一切其他问题一样,当我们换个角度考虑“计算机行为的确定性问题”的时候,会得出不同的结论。

通常当我们仅仅掌握一个系统(是系统论的哲学概念,不是某个计算机软件或硬件系统)的部分信息的时候,这个子系统的边界同样是不确定的。现代计算机通常由大量不同的部分组成,每一个部分都是前述的这类子系统,它们的边界是松散的,仅仅是一个大致类型的边界的约定。举一个例子:比如我们可以通过某个功能取得一块确定大小内存,但我们不可能事先知道得到的内存内保存的具体内容。

另一方面,作为“高级程序设计语言”,其对机器底层的表达能力还是有相当的差距的,尤其当某个语言要保持某个概念的“语义”时。语言通过语义表达的概念,是面向程序员的一种抽象,通常没有直接对应的机器底层机制,而是通过比较复杂的机器行为组合来模拟。语言抽象语义与机器底层机制的断层,就会造成另一种形式的不确定性。

最后,我们要认识到语言本身的社会性。语言的发展过程中,通常会有许多不同的实现给出不同的行为。作为 C++ 语言的特例,它还包括许多从 C 语言的各种实现版本遗传来的历史问题。对于这类不同编译器会给出不同解释和行为的概念,C++ 标准的策略是保留它们到特定的编译器来实现,标准中仅仅给出可能的 C++ 实现的行为选择。

这些不确定性自然会被带到我们写的程序中。

C++ 语言支持的一些默认行为,还有可能与机器配置的地理文化环境有关。比如语言文字,时区,地区习惯等等都会影响 C++ 提供的库的相关行为。这些行为对程序来说通常并不是真正不确定的。程序员要编写国际化/本地化的程序,总是要与这些信息打交道的。

C++ 标准明确定义:
1.3.14 well-formed program [defns.well.formed]

a C++ program constructed according to the syntax rules, diagnosable semantic rules, and the One Definition Rule (3.2).
“完备的 C++ 程序”遵循 C++ 的语法规则,可诊断的语义规则,以及“一次定义原则(ODR)”。
1.3.4 ill-formed program [defns.ill.formed]

input to a C++ implementation that is not a well-formed program (1.3.14).
对于 C++ 实现来说,“病态的 C++ 程序”就是除了“完备的 C++ 程序”之外的文本输入。
1.3.12 undefined behavior [defns.undefined]

behavior, such as might arise upon use of an erroneous program construct or erroneous data, for which this International Standard imposes no requirements. Undefined behavior may also be expected when this International Standard omits the description of any explicit definition of behavior. [Note: permissible undefined behavior ranges from ignoring the situation completely with unpredictable result, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). Many erroneous program constructs do not engender undefined behavior; they are required to be diagnosed. ]
错误的程序构造和数据会导致“未定义行为”,这些程序构造和数据 C++ 标准未强制规定 C++ 实现针对它们进行处理。当 C++ 标准遗漏任何行为的显定义时,也导致“未定义行为”。【注:可接受的未定义行为包括完全忽略产生不确定结果的情况,或者在编译或程序执行时产生环境特有的,有文档描述的行为(可能同时发布出诊断信息),或者终止编译或执行(并发布诊断信息)。许多错误的程序构造不会造成未定义行为,这样的程序需要被诊断。】
1.3.13 unspecified behavior [defns.unspecified]

behavior, for a well-formed program construct and correct data, that depends on the implementation. The implementation is not required to document which behavior occurs. [Note: usually, the range of possible behaviors is delineated by this International Standard. ]
由完备的程序构造和正确的数据产生的某些随实现而定的行为,被称为“未指明的行为”。C++ 实现并不需要提供这些行为的文档。【注:C++标准通常会列出行为可能的范围。】
1.3.5 implementation-defined behavior [defns.impl.defined]

behavior, for a well-formed program construct and correct data, that depends on the implementation and that each implementation shall document.
由完备的程序构造和正确的数据产生的某些随实现而定的行为,被称为“由实现定义的行为”,C++ 标准要求每个实现都对这些行为提供文档说明。
1.3.7 locale-specific behavior [defns.locale.specific]

behavior that depends on local conventions of nationality, culture, and language that each implementation shall document.
依赖于当地国别,文化和语言习惯的行为,被称为“特定于现场的行为”,C++ 标准要求每个实现都对这些行为提供文档说明。

C++ 的初学者经常会问一些貌似“专业”的问题,比如
   int i = 5;
   int j = (++i) + (++i) + (++i);

   int f(int a, int b);
   int i = 5;
   f(++i, ++i);
这样的问题实在不需要多做考虑,而且应该在实际编程实践中尽量避免。因为它们几乎都是“未指明的行为”或“由实现定义的行为”。另一方面,程序的错误或Bugs,通常是由于“未定义的行为”。

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值