如果我有:
unsigned int x;
x -= x;
Run Code Online (Sandbox Code Playgroud)
很明显,x 应该这样表达后是零,但到处看,他们说的行为,这种代码是不确定的,而不是仅仅值x(直到减法之前).
两个问题:
这段代码的行为确实未定义吗?
(例如,代码在兼容系统上崩溃[或更糟]?)
如果是这样,为什么 C表示行为是未定义的,当非常清楚x这里应该为零时?
即不在此定义行为给出的优势是什么?
很明显,编译器可以简单地使用它在变量中认为"方便"的任何垃圾值,并且它可以按预期工作......这种方法有什么问题?
什么是C中的陷阱表示(某些示例可能有帮助)?这适用于C++吗?
float f=3.5;
int *pi = (int*)&f;
Run Code Online (Sandbox Code Playgroud)sizeof(int) == sizeof(float)do f和*pi具有相同的二进制表示/模式?MSVC怎么样?SO 上的各种受人尊敬的高代表用户一直坚持认为读取具有不确定值的变量“始终是 UB”。那么在 C 标准中究竟在哪里提到了这一点?
很明显,不确定的值可能是未指定的值或陷阱表示:
3.19.2
indeterminate value 不确定值
或未指定值或陷阱表示3.19.3
未指定值
本国际标准对在任何情况下选择哪个值没有强加要求的相关类型的有效值
注:未指定值不能是陷阱表示。3.19.4
陷阱表示
不需要表示对象类型值的对象表示
同样很明显,读取陷阱表示会调用未定义的行为,6.2.6.1:
某些对象表示不需要表示对象类型的值。如果对象的存储值具有这样的表示形式并且被没有字符类型的左值表达式读取,则行为未定义。如果这种表示是由没有字符类型的左值表达式修改对象的全部或任何部分的副作用产生的,则行为是未定义的。50) 这种表示称为陷阱表示。
但是,不确定的值不一定包含陷阱表示。事实上,陷阱表示对于使用二进制补码的系统来说是非常罕见的。
C 标准中的哪个地方实际上说读取不确定的值会调用未定义的行为?
我在看C11的非规范性附件J,发现这确实被列为UB的一个案例:
具有自动存储期限的对象的值在不确定时使用(6.2.4、6.7.9、6.8)。
但是,列出的部分是无关紧要的。6.2.4 仅说明有关生命周期和变量值何时变得不确定的规则。类似地,6.7.9 是关于初始化并说明变量的值如何变得不确定。6.8 似乎几乎无关紧要。这些部分都没有包含任何规范性文本,说明访问不确定的值会导致 UB。这是附件 J 中的缺陷吗?
然而,在 6.3.2.1 中有一些关于左值的相关规范文本:
如果左值指定了一个自动存储持续时间的对象,该对象可以使用寄存器存储类声明(从未获取其地址),并且该对象未初始化(未使用初始化程序声明,并且在使用之前未对其进行赋值) ),行为未定义。
但这是一种特殊情况,它仅适用于从未被取地址的自动存储期变量。我一直认为 6.3.2.1 的这一部分是关于不确定值(不是陷阱表示)的唯一 UB 情况。但人们一直坚持“它总是UB”。那么具体是在哪里提到的呢?
我明确指出,我的问题与该问题完全相同。
但不幸的是,我有一个问题,任何答案都没有解决。所以代码是:
#include <string.h>
int foo(void) {
char bar[128];
char *baz = &bar[0];
baz[127] = 0;
return strlen(baz);
}
Run Code Online (Sandbox Code Playgroud)
问题是:此功能的可能输出是什么?
当我运行此代码时,每次给出0,正确的答案是0和127(我仍然不明白为什么?)。
我的问题是,该语句如何有效?我的意思是我们正在计算baz包含一个内存地址的长度,说0xb96eb740这是一个十六进制数,那么我们正在strlen()此地址上查找它的长度是什么?我的意思是我们如何才能找到一个只有数字的地址的长度?
我真的很困惑,想花几个小时来理解它,但仍然听不懂。