我知道未定义的行为可能会导致任何问题,这使得任何包含UB的程序都可能无意义。我想知道是否有任何方法可以确定程序中最早的一点,即未定义的行为可能会导致问题。 这是一个例子来说明我的问题。
void causeUndefinedBehavior()
{
//any code that causes undefined behavior
//every time it is run
char* a = nullptr;
*a;
}
int main()
{
//code before call
//...
causeUndefinedBehavior();
//code after call
//...
}
根据我的理解,可能引发未定义行为的可能时间(不一定表现出来)是:
causeUndefinedBehavior()
时。main()
时。causeUndefinedBehavior()
时。或者,对于每种情况和每种实现,未定义的行为都会被完全区分开来?
另外,如果我注释掉调用causeUndefinedBehavior()
的行,是否会消除UB,或者它是否仍然在程序中,因为编译了包含UB的代码?
答案 0 :(得分:4)
正如您的代码稍微证明的那样,未定义的行为在尝试行为时几乎总是运行时状态的条件。稍微修改一下你的代码会让这很明显:
void causeUndefinedBehavior()
{
//any code that causes undefined behavior
//every time it is run
char* a = nullptr;
*a;
}
int main()
{
srand(time(NULL));
//code before call
//...
if (rand() % 973 == 0)
causeUndefinedBehavior();
//code after call
//...
}
您可以执行此操作一千次或更多次,并且永远不会使UB执行条件跳闸。这并没有改变函数本身显然是UB的事实,但在编译时在调用者的上下文中检测 。
答案 1 :(得分:2)
我认为这取决于未定义行为的类型。会影响结构偏移的事情可能会导致未定义的行为,这会显示触及该结构的任何时间代码。
但是,一般情况下,大多数未定义的行为都发生在运行时,这意味着只有执行该代码才会发生未定义的行为。
For example,尝试修改字符串文字具有未定义的行为:
char* str = "StackOverflow";
memcpy(str+5, "Exchange", 8); // undefined behavior
在memcpy
执行之前,不会发生此“未定义的行为”。它仍然可以编译成完美的代码。
另一个例子是省略具有非void返回类型的函数的返回:
int foo() {
// no return statement -> undefined behavior.
}
这里,正是在foo
返回时发生未定义的行为。 (在这种情况下,在x86上,无论发生在eax
寄存器中的是函数的结果返回值。)
通过启用更高级别的编译器错误报告(例如-Wall
on GCC),可以识别其中许多方案。)
答案 2 :(得分:2)
“未定义的行为”表示语言定义不会告诉您程序将执行的操作。这是一个非常简单的陈述:没有信息。您可以推测您喜欢的实施可能会做什么或不做什么,但除非您的实施记录它的作用,否则您只是在猜测。编程不是猜测;这是关于知道的。如果程序的行为未定义,请修复它。
答案 3 :(得分:1)
虽然它是“未定义的行为”,但在给定特定编译器的情况下,它将具有某种可预测的行为。但由于它未定义,在不同的编译器上,可能会导致在complilation / runtime的任何一点发生该行为
答案 4 :(得分:0)
使任何包含UB的程序可能无意义
不太对劲。程序不能“包含”UB;当我们说“UB”这个简称:程序的行为是不确定的。全部!
因此,该计划从一开始就不仅仅是潜在的,而且实际上是毫无意义的。
[intro.execution]/5
:执行格式良好的程序的符合实现应该产生与具有相同程序和相同输入的抽象机的相应实例的可能执行之一相同的可观察行为。但是,如果任何此类执行包含未定义的操作,此国际标准不要求使用该输入执行该程序的实现(甚至不考虑第一个未定义操作之前的操作)。