小编典典

未定义、未指定和实现定义的行为

all

什么是C 和 C++ 中的 未定义行为(UB)? 未指定的行为实现定义的 行为呢?它们之间有什么区别?


阅读 219

收藏
2022-03-06

共1个答案

小编典典

未定义的行为 是 C 和 C 语言的那些方面之一,可能会让来自其他语言的程序员感到惊讶(其他语言试图更好地隐藏它)。基本上,即使许多 C
编译器不会报告程序中的任何错误,也可以编写行为无法预测的 C++ 程序!

我们来看一个经典的例子:

#include <iostream>

int main()
{
    char* p = "hello!\n";   // yes I know, deprecated conversion
    p[0] = 'y';
    p[5] = 'w';
    std::cout << p;
}

该变量p指向字符串字面量"hello!\n",下面的两个赋值尝试修改该字符串字面量。这个程序有什么作用?根据 C++ 标准的第 2.14.5 节第
11 段,它调用 未定义的行为

尝试修改字符串文字的效果是未定义的。

我可以听到人们尖叫“但是等等,我可以编译这个没有问题并得到输出yellow”或“你是什么意思未定义,字符串文字存储在只读内存中,所以第一次分配尝试导致核心转储”。这正是未定义行为的问题。基本上,一旦您调用未定义的行为(甚至是鼻恶魔),该标准允许任何事情发生。如果根据你的语言心理模型存在“正确”的行为,那么该模型就是错误的;C++
标准拥有唯一的投票权,句号。

未定义行为的其他示例包括访问超出其边界的数组、取消引用空指针、在对象的生命周期结束后访问对象或编写据称聪明的表达式,如i+++ ++i.

C++ 标准的 1.9 节还提到了未定义行为的两个不太危险的兄弟, 未指定行为实现定义行为

本国际标准中的语义描述定义了一个参数化的非确定性抽象机。

抽象机的某些方面和操作在本国际标准中描述为 实现定义
(例如,sizeof(int))。这些构成了抽象机的参数。每个实现都应包括描述其在这些方面的特征和行为的文档。

抽象机的某些其他方面和操作在本国际标准中描述为 未指定
(例如,函数参数的评估顺序)。在可能的情况下,本国际标准定义了一组允许的行为。这些定义了抽象机器的不确定性方面。

本国际标准中将某些其他操作描述为 未定义 (例如,取消引用空指针的效果)。[
本国际标准对包含未定义行为的程序的行为没有任何要求。尾注 ]

具体来说,第 1.3.24 节规定:

允许的未定义行为的范围从 完全忽略具有不可预测结果的情况
,到在翻译或程序执行期间以环境特征的记录方式表现(有或没有发出诊断消息),到终止翻译或执行(有发出的诊断消息)。

2022-03-06