Luc*_*ore 47 c++ pointers language-lawyer
在执行指针算术时有很多未定义/未指定行为的示例 - 指针必须指向同一个数组(或者一个超过结尾),或者在同一个对象内,限制何时可以根据上述进行比较/操作等
以下操作定义明确吗?
int* p = 0;
p++;
Run Code Online (Sandbox Code Playgroud)
Col*_*mbo 36
§5.2.6/ 1:
1除非对象的类型为bool[..] ,否则操作数对象的值将通过添加来修改.
涉及指针的附加表达式在第5.7/5节中定义:
如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出; 否则,行为未定义.
gna*_*729 15
对"未定义行为"的含义似乎很少了解.
在C,C++和Objective-C等相关语言中,有四种行为:存在由语言标准定义的行为.存在实现定义的行为,这意味着语言标准明确表示实现必须定义行为.存在未指定的行为,其中语言标准表示可能存在多种行为.并且存在未定义的行为,其中语言标准没有说明结果.因为语言标准没有说明结果,所以任何事情都可能发生在未定义的行为上.
这里的一些人认为"未定义的行为"意味着"发生了不好的事情".那是错的.这意味着"任何事情都可能发生",其中包括"可能发生的坏事",而不是"必须发生的事情".在实践中,它意味着"当你测试你的程序时没有什么不好的事情发生,但是一旦它被发送给客户,一切都会崩溃".由于任何事情都可能发生,编译器实际上可以假设代码中没有未定义的行为 - 因为它是真的,或者它是假的,在这种情况下任何事情都可能发生,这意味着由于编译器的错误假设仍然发生正确.
有人声称,当p指向3个元素的数组,并计算p + 4时,不会发生任何不良事件.错误.这是你的优化编译器.说这是你的代码:
int f (int x)
{
int a [3], b [4];
int* p = (x == 0 ? &a [0] : &b [0]);
p + 4;
return x == 0 ? 0 : 1000000 / x;
}
Run Code Online (Sandbox Code Playgroud)
如果p指向a [0],则评估p + 4是未定义的行为,但如果指向b [0]则不是.因此允许编译器假设p指向b [0].因此允许编译器假设x!= 0,因为x == 0导致未定义的行为.因此,允许编译器在return语句中删除x == 0检查,并返回1000000/x.这意味着当您调用f(0)而不是返回0时,程序会崩溃.
另一个假设是,如果你增加一个空指针然后再次递减它,结果再次是一个空指针.又错了.除了增加空指针可能只是在某些硬件上崩溃的可能性之外,接下来是这样的:由于递增空指针是未定义的行为,编译器检查指针是否为空并且只有在指针不是空指针时才递增指针,所以p + 1再次是一个空指针.通常它会对递减执行相同的操作,但作为一个聪明的编译器,它注意到如果结果是空指针,p + 1总是未定义的行为,因此可以假设p + 1不是空指针,因此可以省略空指针检查.这意味着,如果p是空指针,则(p + 1) - 1不是空指针.
Pet*_*ter 13
指针的操作(如递增,添加等)通常仅在指针的初始值和结果指向同一数组的元素(或指向最后一个元素的一个元素)时才有效.否则结果是未定义的.各种运营商在标准中都有各种条款,包括增量和增加.
(有一些例外,例如将0添加到NULL或从NULL中减去零是有效的,但这不适用于此).
NULL指针不指向任何内容,因此递增它会给出未定义的行为("otherwise"子句适用).