请考虑以下声明:
*((char*)NULL) = 0; //undefined behavior
Run Code Online (Sandbox Code Playgroud)
它明确地调用未定义的行为.在给定的程序中是否存在这样的语句意味着整个程序是未定义的,或者一旦控制流命中这个语句,该行为只会变得不确定?
如果用户从未输入数字,3是否可以明确定义以下程序?
while (true) {
int num = ReadNumberFromConsole();
if (num == 3)
*((char*)NULL) = 0; //undefined behavior
}
Run Code Online (Sandbox Code Playgroud)
或者,无论用户输入什么,它都是完全未定义的行为?
此外,编译器是否可以假定在运行时永远不会执行未定义的行为?这样可以及时推理:
int num = ReadNumberFromConsole();
if (num == 3) {
PrintToConsole(num);
*((char*)NULL) = 0; //undefined behavior
}
Run Code Online (Sandbox Code Playgroud)
在这里,编译器可以推断,以防num == 3我们总是调用未定义的行为.因此,这种情况必须是不可能的,并且不需要打印该号码.整个if声明可以优化.根据标准,是否允许这种向后推理?
c++ dead-code undefined-behavior language-lawyer unreachable-code
我不太明白为什么我不能除以零例外:
int d = 0;
d /= d;
Run Code Online (Sandbox Code Playgroud)
我本来希望得到除以零的除法运算,但是反而d == 1。
为什么在什么时候不d /= d将被零除d == 0?
c++ division divide-by-zero compiler-optimization undefined-behavior
我们都听过警告,如果你在C或C++中调用未定义的行为,任何事情都可能发生.
这是否仅限于任何运行时行为,还是包括任何编译时行为?特别是,编译器在遇到调用未定义行为的构造时,允许拒绝代码(在标准中没有其他要求的情况下这样做),甚至崩溃?
看完这个讨论后,我意识到我几乎完全误解了这件事:)
由于C++抽象机器的描述不够严格(例如,与JVM规范进行比较),如果无法得到准确的答案,我宁愿希望得到关于合理"好"的规则的非正式澄清(非恶意) )实施应遵循.
标准中关于实现自由的第1.9部分的关键概念被称为as-if规则:
只要可以从程序的可观察行为中确定,结果就好像符合要求一样,实施可以自由地忽略本标准的任何要求.
根据标准(I引用n3092),术语"可观察行为"表示以下内容:
- 严格根据抽象机的规则来评估对易失性对象的访问.
- 在程序终止时,写入文件的所有数据应与根据抽象语义产生的程序执行的可能结果之一相同.
- 交互设备的输入和输出动态应以在程序等待输入之前提示输出实际传送的方式进行.构成交互设备的是实现定义的.
因此,粗略地说,应保留易失性访问操作和io操作的顺序和操作数; 实现可以在保存这些不变量的程序中进行任意更改(与抽象c ++机器的某些允许行为相比)
期望非恶意实现对操作进行足够广泛的处理是否合理(例如,来自用户代码的任何系统调用都被视为此类操作)?(例如,如果RAII包装器不包含挥发物,则编译器不会丢弃RAII互斥锁定/解锁)
"行为观察"应该从用户定义的c ++程序级别深入到库/系统调用中有多深?现在的问题是,当然,只有该库的调用不打算有从用户角度来看IO /挥发性接入(例如,作为新/删除操作),而且可能(通常如此)访问挥发,或在图书馆/系统IO 实现.应该从用户的角度来看,编译器将这类电话(并考虑副作用,如没有可观察到的),或从"库"的观点(以及考虑的副作用观察到的)?
如果我需要通过编译器,以防止一些代码消除,这是一个好的做法,是不会问上面的所有问题,并简单地增加(可能是假的)挥发性存取操作(换行需要挥发的方法的行动,并呼吁他们对挥发性情况我在任何情况下似乎可疑?
或者我完全错了,除了标准明确提到的情况(作为副本消除)之外,编译器不允许删除任何c ++代码
考虑这个程序:
#include <stdio.h>
int main(void)
{
int x;
while ( 1 == scanf("%d", &x) )
printf("%c\n", "hello"[x]);
}
Run Code Online (Sandbox Code Playgroud)
编译器必须成功编译,因为程序没有UB,只要用户不输入范围之外的任何数字0- 4.
但是,根据这个线程, UB可以及时返回.现在考虑这个程序:
int main(void)
{
printf("hello\n");
"hello"[6];
}
Run Code Online (Sandbox Code Playgroud)
对此程序的任何调用都会导致未定义的行为,并且因为这可能是时间旅行,所以此程序在任何调用中的整个行为都是未定义的.因此,编译器可以拒绝该程序而不生成可执行文件吗?(我们可能会说UB回到编译阶段!)
考虑以下代码:
int main()
{
printf("Hello World!\n");
int i;
i = i++ + ++i; // UB
}
Run Code Online (Sandbox Code Playgroud)
此代码是否保证打印"Hello World!"?最后一行调用未定义的行为,但是这会使整个程序无效吗?
我找到了这个,但问题是关于C++.这是关于C.
它不是未定义的行为和序列点的重复,因为它是C++.答案可能相同或不同,但这个问题是关于C.