当一个指针到特定类型的(比如int,char,float,..)被递增,其值增加该数据类型的大小.如果void指向大小数据的指针x递增,它如何获得指向x前面的字节?编译器如何知道添加x指针的值?
在执行指针算术时有很多未定义/未指定行为的示例 - 指针必须指向同一个数组(或者一个超过结尾),或者在同一个对象内,限制何时可以根据上述进行比较/操作等
以下操作定义明确吗?
int* p = 0;
p++;
Run Code Online (Sandbox Code Playgroud) 这段代码:
int *p = nullptr;
p++;
Run Code Online (Sandbox Code Playgroud)
导致未定义的行为,如在增加一个明确定义的空指针中讨论的那样?
但在解释研究员为什么要避免UB的时候,除了说它很糟糕,因为UB意味着任何事情都可能发生,我想举一些例子证明它.我有很多他们可以访问超出限制的数组,但我找不到一个.
我甚至试过了
int testptr(int *p) {
intptr_t ip;
int *p2 = p + 1;
ip = (intptr_t) p2;
if (p == nullptr) {
ip *= 2;
}
else {
ip *= -2;
} return (int) ip;
}
Run Code Online (Sandbox Code Playgroud)
在一个单独的编译单元中希望优化编译器会跳过测试,因为当p为null时,line int *p2 = p + 1;是UB,并且允许编译器假定代码不包含UB.
但是gcc 4.8.2(我没有可用的gcc 4.9)和clang 3.4.1都回答了正值!
有人会建议一些更聪明的代码或其他优化编译器在增加空指针时出现问题吗?
在这个答案的评论中,据说使用如下的联合将整数分割成它们的字节将是未定义的行为.在那个地方给出的代码是相似的,虽然与此不相同,请注意我是否更改了代码的未定义行为相关方面.
union addr {
uint8_t addr8[4];
uint32_t addr32;
};
Run Code Online (Sandbox Code Playgroud)
到目前为止,我认为这将是一个很好的做法,addr = {127, 0, 0, 1};并得到相应 uint32_t的回报.(我承认根据我的系统的字节顺序,这可能产生不同的结果.但问题仍然存在.)
这是未定义的行为吗?如果是这样,为什么?(我不知道C++中的UB是什么意思是访问非活动的联盟成员.)
C99
C++ 03
然而
结论
uint8_t[4]和uint32_t不是同一类型(我猜,一个严格的混叠的东西)(加上两个都不是POD结构/联合)上面确实是UB?C++ 11