6

我有一个来自这里的代码片段:

volatile int volatileInt;
int usualInt;

void function (unsigned x, unsigned y, unsigned z)
{
    volatileInt = 0;
    usualInt = (x % y) / z;
}

int main()
{
    function(rand(), rand(), rand());
}

我用 Visual C++ 10 编译/O2并得到这个反汇编:

00403940  push        ebx  
00403941  push        esi  
   276:     function(rand(), rand(), rand());
00403942  mov         esi,dword ptr [__imp__rand (4050C0h)]  
00403948  push        edi  
00403949  call        esi  
0040394B  mov         edi,eax  
0040394D  call        esi  
0040394F  mov         ebx,eax  
00403951  call        esi  
00403953  xor         edx,edx  
00403955  div         eax,ebx  <<<< possible UB
00403957  mov         dword ptr [volatileInt (4074D0h)],0  
00403961  mov         eax,edx  
00403963  xor         edx,edx  
00403965  div         eax,edi  <<<< possible UB
00403967  pop         edi  
00403968  pop         esi  
00403969  pop         ebx  
0040396A  mov         dword ptr [usualInt (4074CCh)],eax  
   277:     return 0;
0040396F  xor         eax,eax
00403971  ret  

请注意,如果它们的第二个操作数在运行时为零,则有两个操作 - “mod”和“div”可能会产生 UB。在发出的代码中,两者都使用操作码实现,这些div操作码将触发结构化异常并使程序崩溃,第二个操作数为零。

第一个div是在volatile int变量修改之前,第二个是在volatile int修改之后。

因此,如果x为零,则程序在不修改的情况下崩溃,volatile int但如果x为非零且y为零,则程序修改volatile int然后崩溃。

因此,根据是否x为零y,程序将表现出不同的可观察行为。

是否允许将代码与可能的 UB 与影响可观察行为的代码交错?

4

2 回答 2

7

是的,这个实现是允许的。见 1.9/5:

执行格式良好的程序的一致实现应产生与具有相同程序和相同输入的抽象机的相应实例的可能执行之一相同的可观察行为。但是,如果任何此类执行包含未定义的操作,则本国际标准对使用该输入执行该程序的实现没有要求(甚至不考虑第一个未定义操作之前的操作)。

于 2012-07-18T09:37:51.127 回答
5

我认为第 1.9:4 条在这里是相关的:

本国际标准中将某些其他操作描述为未定义的(例如,尝试修改 const 对象的效果)。[注:本国际标准对包含未定义行为的程序的行为没有要求。——尾注]

据我了解,这意味着如果程序执行最终导致未定义的行为,那么程序的整个可观察行为都是未定义的。

于 2012-07-18T09:28:37.073 回答