gpt4 book ai didi

c - C的未指定,未定义和实现定义的行为WIKI

转载 作者:行者123 更新时间:2023-12-01 19:07:22 25 4
gpt4 key购买 nike

尽管关于SO的这个主题有很多链接,但我认为还缺少一些内容:用通俗易懂的语言清楚地解释未指定行为(UsB),未定义行为(UB)和实现定义的行为(IDB)之间的区别),并详细但容易地解释了所有用例和示例。

注意:为了使本WIKI紧凑起见,我把UsB缩写了起来,但是不要期望在其他地方看到它。

我知道这似乎是其他帖子的重复(更接近的是this),但是在任何人将其标记为重复之前,请考虑我已经发现的所有材料有什么问题(我将要从这篇文章中做出社区维基):


太多分散的例子。例子当然不错,但是有时候人们找不到适合他问题的例子,因此它们可能会令人困惑(尤其是对于新手)。
示例通常只是很少解释的代码。在这类棘手的问题上,尤其是对于(相对)新手,采用自上而下的方法可能更好:首先用抽象(但不合法)的描述进行清晰,简单的解释,然后用一些简单的示例说明其触发某些行为的原因。
有些帖子经常混用C和C ++示例。 C和C ++有时与他们认为UsB,UB和IDB的含义不一致,因此对于不精通这两种语言的人来说,这可能会误导一个例子。
当给出UsB,UB和IDB的定义时,通常只是标准的明文引用,有时对于新手来说可能不清楚或太难理解。
有时对标准的引用是不完整的。许多帖子仅引用了对当前问题有用的部分的标准,虽然很好,但缺乏通用性。此外,对标准的引用通常没有任何解释(对初学者不利)。


由于我自己不是这个问题的超级专家,因此我将进行社区WIKI,以便任何有兴趣的人都可以做出贡献并改善答案。

为了不破坏创建对初学者友好的结构化WIKI的目的,我希望张贴者在编辑WIKI时遵循几个简单的准则:


分类您的用例。尝试将示例/代码放在现有的类别下(如果适用),否则创建一个新的类别。
首先是普通单词的描述。首先用简单的文字(当然不要过分简化-质量第一!)来描述您要说明的示例或要点。然后放入代码样本或引用。
通过引用引用标准。不要发布各种标准的代码段,但要提供明确的参考信息(例如C99 WG14 / N ...第1.4.7节,第...段),并在可能的情况下发布指向相关资源的链接。
喜欢免费的在线资源。如果您想引用书籍或非免费可用的资源(可以提高WIKI的质量),请尝试添加一些指向免费资源的链接。这对于ISO标准尤其重要。欢迎您添加官方标准的链接,但也尝试向免费提供的草稿中添加等效的链接。并且,请不要使用对官方标准的引用来代替草稿的链接,而应添加这些内容。甚至某些大学的某些计算机科学系也没有ISO标准的副本,更不用说大多数程序员了!
除非确实必要,否则不要发布代码。仅当仅使用普通英语的说明会感到尴尬或不清楚时,才可使用邮政编码。尝试将代码示例限制为单行代码。将链接发布到其他SO Q&A。
不要发布C ++示例。我希望这成为C的常见问题解答(但是,如果有人想为C ++启动双线程,那将是不错的选择)。欢迎使用与C ++相关的差异,但仅作为旁注。那就是在您彻底解释了C案例之后,如果可以在切换到C ++时对C程序员有所帮助,则可以添加一些有关C ++的语句,但是我不想看到包含20%以上C ++内容的示例。通常,简单的注释如“(在这种情况下,C ++的行为会有所不同)”加上相关的链接就足够了。


由于我对SO还很陌生,所以我希望通过这种方式进行问与答不会违反任何规则。抱歉,是这种情况。国防部欢迎让我知道它。

最佳答案

C标准以如下方式定义了UsB,UB和IDB:
未指明的行为(UsB)
这是一种行为,标准为该行为提供了一些替代方案,实现必须选择这些替代方案,但是它并没有规定如何以及何时进行选择。换句话说,该实现必须接受触发该行为的用户代码而不会出错,并且必须遵守该标准给出的替代方法之一。
请注意,该实现不需要记录所做选择的任何内容。这些选择也可能不确定,也可能取决于编译器选项。
总结一下:该标准提供了一些选择的可能性,实现选择何时以及如何选择和应用特定的选择。
请注意,该标准可能提供了大量替代方案。典型示例是未明确初始化的局部变量的初始值。该标准说,未指定此值,只要它是变量数据类型的有效值即可。
更具体地说,考虑一个int变量:实现可以自由选择任何int值,并且该选择可以是完全随机的,不确定的,也可以不受实现的要求,这不是必需的记录任何有关它的信息。只要实现保持在标准规定的限制内,就可以,用户不能抱怨。
未定义行为(UB)
顾名思义,这是C标准不强加或保证程序将执行或应执行的操作的情况。所有赌注都关闭了。这样的情况:

导致程序错误或不可移植

不需要绝对的实现


这真是一个令人讨厌的情况:只要有一段代码具有未定义的行为,就会认为整个程序是错误的,并且标准允许执行所有操作。
换句话说,只要涉及到引发UB的程序,UB原因的存在就可以使实现完全忽略该标准。
请注意,这种情况下的实际行为可能涵盖了无限的可能性,以下内容绝不是详尽的清单:

可能会发出编译时错误。
可能会发出运行时错误。
该问题被完全忽略(这可能会导致程序错误)。
编译器无声地将UB代码丢弃作为优化。
您的硬盘可能已格式化。
您的计算机可能会删除您的银行帐户,并询问女友约会的日期。

我希望最后两个(半数)项目可以使您对UB的呆板感觉有所了解。即使大多数实现都不会插入必要的代码来格式化硬盘,但真正的编译器确实可以优化!
术语注释:有时人们会争辩说,该标准在其实现/系统/环境工作中以文件化的方式将某些代码视为UB的来源,因此它实际上并不是UB。这种推理是错误的,但这是一个常见的(并且在某种程度上可以理解的)误解:当术语UB(以及UsB和IDB)在C上下文中使用时,它是一个技术术语,其确切含义由标准定义( s)。特别是“未定义”一词失去了日常意义。因此,显示错误或不可移植的程序产生“定义良好”行为作为反例的例子没有意义。如果尝试,您真的会错过重点。 UB意味着您失去了该标准的所有保证。如果您的实现提供了扩展,则您的保证仅是实现的保证。如果使用该扩展名,则您的程序不再是符合标准的C程序(在某种意义上,它不再是C程序,因为它不再遵循标准!)。
未定义行为的有用性
关于UB的一个常见问题是:“如果UB太讨厌了,为什么面对UB时,标准强制执行错误?”
首先,优化。允许实现不检查UB的可能原因,可以进行许多优化,这些优化使C程序非常有效。这是C的功能之一,尽管它使C成为初学者的许多陷阱。
其次,标准中UB的存在允许一致的实现提供对C的扩展,而不会被视为整体不合格。
只要实现的行为符合一致性程序的要求,它本身就是一致性的,尽管它可能会提供在特定平台上有用的非标准功能。当然,使用这些工具的程序将是不可移植的,并且将依赖于已记录的UB,即,根据标准是UB的行为,但是将实现记录为扩展。
实现定义的行为(IDB)
这种行为可以用类似于UsB的方式来描述:该标准提供了一些替代方案,实现选择了一种,但是需要实现来准确记录选择的方式。
这意味着必须向阅读其编译器文档的用户提供足够的信息,以准确预测在特定情况下会发生什么。
请注意,没有完全记录IDB的实现不能认为是符合要求的。符合标准的实现必须准确记录在标准声明IDB的任何情况下发生的情况。

未指明行为的示例
评估顺序
函数参数
函数参数的求值顺序未指定EXP30-C
例如,在c(a(), b());中,未指定在a之前还是之后调用函数b。唯一的保证是两者都在c函数之前被调用。

未定义行为的示例
指针
解引用空指针
空指针用于指示指针未指向有效内存。因此,尝试通过空指针读取或写入内存没有太大意义。
从技术上讲,这是不确定的行为。但是,由于这是错误的非常常见的来源,因此大多数C环境都确保大多数取消引用空指针的尝试都会立即使程序崩溃(通常是由于分段错误而将其杀死)。由于对数组和/或结构的引用涉及指针算法,因此此保护措施并不完善,因此即使使用现代工具,取消引用空指针也可能会格式化硬盘。
取消引用未初始化的指针
就像空指针一样,在显式设置其值之前取消对指针的引用是UB。与null指针不同,大多数环境不提供针对此类错误的任何安全网,除非编译器可以发出警告。如果仍然编译代码,则很可能会遇到UB的全部麻烦。
取消引用无效的指针
无效的指针是包含不在任何分配的内存区域内的地址的指针。创建无效指针的常见方法是调用free()(在调用之后,指针将是无效的,这几乎是调用free()的意义),或者使用指针算术获得超出限制的地址分配的内存块。
这是指针引用UB的最邪恶的变体:没有安全网,没有编译器警告,仅存在代码可以执行任何操作的事实。通常,它确实如此:大多数恶意软件攻击都在程序中使用这种UB行为,以使程序按其希望的方式运行(例如安装特洛伊木马程序,键盘记录程序,对硬盘驱动器进行加密等)。这种UB格式化硬盘的可能性非常大!
抛弃constness
如果将一个对象声明为const,则会向编译器作出承诺,即永远不会更改该对象的值。在许多情况下,编译器会发现这种无效的修改并向我们喊叫。但是,如果像下面的代码片段那样丢弃constness:

int const a = 42;
...
int* ap0 = &a; //< error, compiler will tell us
int* ap1 = (int*)a; //< silences the compiler
...
*ap1 = 43; //< UB ==> program crash?

编译器可能无法跟踪此无效访问,无法将代码编译为可执行文件,并且仅在运行时才会检测到无效访问并导致程序崩溃。
2类
在这里放一个标题!
将您的解释放在这里!

实现定义的行为的示例
1类
在这里放一个标题!
将您的解释放在这里!

关于c - C的未指定,未定义和实现定义的行为WIKI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18420753/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com