4 回答
TA贡献1900条经验 获得超5个赞
register
编辑:
如果lvalue指定可以用寄存器存储类声明的具有自动存储持续时间的对象(从未使用其地址),且该对象未初始化(未使用初始化器声明,且未在使用前对其执行赋值),则行为未定义。
unsigned char a, b;memcpy(&a, &b, 1);a -= a;
这里的地址 a
和 b
所以它们的价值是不确定的。 自 unsigned char
从未有不确定值只是未指定的陷阱表示,任何 unsigned char
可能会发生。 最后 a
必持有价值 0
.
编辑2: a
b
3.19.3 未指定值
在本国际标准不要求在任何情况下选择值的相关类型的有效值
TA贡献1830条经验 获得超9个赞
C标准为编译器提供了很大的空间来执行优化。如果假设程序的天真模型将未初始化的内存设置为一些随机位模式,并且所有操作都按照编写的顺序执行,那么这些优化的结果可能会令人惊讶。
注意:以下示例仅有效,因为x
它的地址从来没有被占用过,所以它是“注册式的”。如果x
有陷阱表示;这种情况很少发生在无符号类型(它至少需要“浪费”一点存储空间,并且必须有文档记录),而且不可能用于unsigned char
。如果x
如果有符号类型,则实现可以定义在-(2)之间不是数字的位模式。恩-1-1)和2恩-1-1作为陷阱代表。
编译器试图将寄存器分配给变量,因为寄存器比内存更快。由于程序可能使用比处理器拥有寄存器更多的变量,编译器执行寄存器分配,从而导致在不同时间使用相同寄存器的不同变量。考虑程序片段
unsigned x, y, z; /* 0 */y = 0; /* 1 */z = 4; /* 2 */x = - x; /* 3 */y = y + z; /* 4 */x = y + 1; /* 5 */
当计算第3行时,x
还没有初始化,因此(编译器的原因)第3行必须是某种侥幸,这是由于编译器不够聪明而无法解决的其他情况。自z
不在第4行之后使用,并且x
如果不在第5行之前使用,则可以对两个变量使用相同的寄存器。因此,这个小程序被编译成寄存器上的以下操作:
r1 = 0;r0 = 4;r0 = - r0;r1 += r0;r0 = r1;
的最终价值x
的最终值r0
的最终价值y
的最终值r1
。这些值是x=-3和y=-4,而不是如果x
已经正确初始化了。
关于更详细的示例,请考虑以下代码片段:
unsigned i, x;for (i = 0; i < 10; i++) { x = (condition() ? some_value() : -x);}
假设编译器检测到condition
没有副作用。自condition
不修改x
,编译器知道循环中的第一次运行不可能访问x
因为它还没有初始化。因此,循环体的第一次执行相当于x = some_value()
没有必要测试条件。编译器可能会编译这段代码,就好像您已经编写了
unsigned i, x;i = 0; /* if some_value() uses i */x = some_value();for (i = 1; i < 10; i++) { x = (condition() ? some_value() : -x);}
在编译器中建模的方式是考虑任何依赖于x
有无论什么价值都是方便的只要x
未初始化。由于未初始化变量的行为是未定义的,而不是仅具有未指定值的变量,所以编译器不需要跟踪任何方便的值之间的任何特殊的数学关系。因此,编译器可以这样分析上面的代码:
- 在第一次循环迭代中,
未初始化的x
被评估。-x
有未定义的行为,所以它的价值是什么-是方便。-x
- 优化规则
应用,以便将此代码简化为condition ? value : value
condition; value
.
当遇到问题中的代码时,这个编译器会在x = - x
的值。-x
什么都方便。这样就可以优化分配。
我还没有寻找像上面所描述的编译器的例子,但是这是好的编译器尝试做的优化的类型。我不会惊讶地遇到一个。下面是一个你的程序崩溃的编译器的不太合理的例子。(如果您在某种高级调试模式下编译您的程序,可能就不会那么难以置信了。)
此假设编译器映射不同内存页中的每个变量,并设置页属性,以便读取未初始化的变量会导致调用调试器的处理器陷阱。对变量的任何赋值首先要确保其内存页被正常映射。此编译器不尝试执行任何高级优化-它处于调试模式,目的是很容易地定位bug,如未初始化的变量。什么时候x = - x
计算,则右侧将引发陷阱并触发调试器.
TA贡献1839条经验 获得超15个赞
是的,程序可能会崩溃。例如,可能会出现陷阱表示(无法处理的特定位模式),这些表示可能会导致CPU中断,而未处理的则可能导致程序崩溃。
(6.2.6.1在后期的C11草案中说)某些对象表示不需要表示对象类型的值。如果对象的存储值具有这样的表示形式,并且由不具有字符类型的lvalue表达式读取,则该行为是未定义的。如果这样的表示是由一个副作用产生的,该副作用通过不具有字符类型的lvalue表达式修改对象的全部或任何部分,则该行为是未定义的。50)这种表示称为陷阱表示。
TA贡献1878条经验 获得超4个赞
unsigned int x
x -= x
- 4 回答
- 0 关注
- 815 浏览
添加回答
举报