我正在阅读关于未定义行为的本文,其中一个示例"优化"看起来非常可疑:
Run Code Online (Sandbox Code Playgroud)if (arg2 == 0) ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero"))); /* No overflow is possible */ PG_RETURN_INT32((int32) arg1 / arg2);图2:意外的优化使
src/backend/utils/adt/int8.cPostgreSQL中的除零检查无效.该召唤ereport(ERROR, :::)将引发异常.
从本质上讲,编译器假定这ereport将返回,并删除arg2 == 0,因为分工的存在意味着一个非零分母检查,即arg2 != 0.
这是一个有效的优化吗?编译器是否可以自由地假设函数将始终返回?
编辑:整个事情取决于ereport,因此描述:
84 /*----------
85 * New-style error reporting API: to be used in this way:
86 * ereport(ERROR,
87 * (errcode(ERRCODE_UNDEFINED_CURSOR),
88 * errmsg("portal \"%s\" not found", stmt->portalname),
89 * ... other errxxx() fields as …Run Code Online (Sandbox Code Playgroud) 据说无限循环for(;;);是未定义的行为.
来自http://en.cppreference.com/w/cpp/language/memory_model
在有效的C++程序中,每个线程最终都会执行以下操作之一:
- 终止
- 调用I/O库函数
- 读取或修改易失性对象
- 执行原子操作或同步操作
没有执行任何这些可观察的行为,任何执行线程都不能永远执行.
请注意,这意味着具有无限递归或无限循环的程序(无论是作为for语句实现还是通过循环goto或其他方式)具有未定义的行为.
但是如果它在共享库中调用函数呢?
for(;;) sofunc();
该函数可以执行任何类型的阻塞I/O或抛出异常.
在这种情况下,编译器是否假定循环具有一些可观察的行为?
以下测试代码在VS中使用调试或发布以及GCC中都能正确执行.它也适用于带调试的ICC,但在启用优化时却没有(-O2).
#include <cstdio>
class tClassA{
public:
int m_first, m_last;
tClassA() : m_first(0), m_last(0) {}
~tClassA() {}
bool isEmpty() const {return (m_first == m_last);}
void updateFirst() {m_first = m_first + 1;}
void updateLast() {m_last = m_last + 1;}
void doSomething() {printf("should not reach here\r\n");}
};
int main() {
tClassA q;
while(true) {
while(q.isEmpty()) ;
q.doSomething();
}
return 1;
}
Run Code Online (Sandbox Code Playgroud)
它应该停在while(q.isEmpty()).-O2然而,当在ICC(发布)下启用时,它无限地开始"doSomething".
由于这是单线程程序并且 isEmpty()应该被评估为true,我发现ICC没有理由以这种方式行事?我想念什么吗?
我偶然遇到过这样的情况:
while (true) {
while (age == 5); //What does this semi-colon indicate?
//Code
//Code
//Code
}
Run Code Online (Sandbox Code Playgroud)
这while(true)表明这是一个无限循环,但我无法理解while条件完成后的分号是什么,是不是等于这个?:
while (age == 5) { }
//Code
//Code
Run Code Online (Sandbox Code Playgroud)
换句话说,它是否意味着while循环是无用的,因为它永远不会进入块?
for (;;);C中的未定义行为是无限循环吗?(它适用于C++,但我不知道C.)
什么时候编译器可以进行优化会导致我的C++代码表现出错误的行为,如果没有执行这些优化,那么这些行为将不会出现?例如,volatile在某些情况下不使用会导致程序行为不正确(例如,不从内存重新读取变量的值,而只读取一次并将其存储在寄存器中).但是,在开启最具侵略性的优化标志之前,还有其他陷阱应该知道吗,然后想知道为什么程序不再起作用了?
我正在讨论使用具有不确定值的变量导致未指定的行为,而不是未定义的行为,如此处所述。这假设具有自动存储持续时间的变量已获取其地址并且陷阱表示不适用。
在具体情况下,讨论了ptr之后发生的情况free(ptr),在这种情况下 C17 6.2.4 适用:
当指针指向(或刚刚过去)的对象到达其生命周期结束时,指针的值变得不确定。
我做了这个例子:
#include <stdlib.h>
#include <stdio.h>
int main (void)
{
int* ptr = malloc(sizeof *ptr);
int* garbage;
int*volatile* dummy = &garbage; // take the address
free(ptr);
puts("This should always print");
fflush(stdout);
if(ptr == garbage)
{
puts("Didn't see that one coming.");
}
else
{
puts("I expect this to happen");
}
puts("This should always print");
}
Run Code Online (Sandbox Code Playgroud)
我提出的论点是,从理论上讲,我们无法知道是ptr == garbage真是假,因为此时它们都是不确定的。因此编译器甚至不需要读取这些内存位置 - 因为它可以推断两个指针都保存不确定的值,所以在优化期间可以根据需要自由地将表达式评估为 true 或 false。(实际上大多数编译器可能不会这样做。)
我在 x86_64 编译器 …
正如在这个问题中所讨论的,C++ 11优化了无限循环.
然而,在具有单一目的的嵌入式设备中,无限循环是有意义的并且实际上经常被使用.即使是完全空的while(1);也适用于看门狗辅助复位.终止但空循环在嵌入式开发中也很有用.
是否有一种优雅的方式来专门告诉编译器不要删除空循环或无限循环,而不完全禁用优化?
您好我有以下代码,我使用-fopenmp标志用gcc(> 4.2)编译:
int main(void)
{
#pragma omp parallel for
int i;
for(i=0;i<4;i++) while(1);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我在OSX Lion(版本1.7.3,llvm-gcc 4.2.1)和CentOS 6.2上获得了SIGSEGV.我在这做错了什么?谢谢