非数组类型的指针算术

Ser*_*eyA 6 c++ language-lawyer type-punning char-pointer

让我们考虑以下代码:

struct Blob {
    double x, y, z;
} blob;

char* s = reinterpret_cast<char*>(&blob);
s[2] = 'A';
Run Code Online (Sandbox Code Playgroud)

假设sizeof(double)为8,此代码是否会触发未定义的行为?

小智 5

引自N4140(大致是C++ 14):

3.9类型[basic.types]

2对于具有普通可复制类型的任何对象(基类子对象除外)T,无论对象是否保持有效的类型值,T组成对象的基础字节(1.7)都可以复制到char或的数组中unsigned char.42如果阵列的内容charunsigned char将被复制回对象,该对象随后应保持其原始值.

42)例如,使用库函数(17.6.1.2)std::memcpystd::memmove.

3对于任何平凡复制的类型T,如果两个指针T指向不同T对象obj1obj2,其中既不obj1也不obj2是碱基-类子对象,如果构成底层字节(1.7)obj1被复制到obj2,43 obj2随后应保持相同的值obj1.[ 例子: ...]

43)例如,使用库函数(17.6.1.2)std::memcpystd::memmove.

原则上,这确实允许直接赋值,s[2]如果你采取的位置,s[2]间接要求赋值是等同于将所有其他一些复制Blob到一个数组中,除了第三个字节之外恰好是字节相同,并将其复制到你的Blob:你没有分配给s[0],s[1]等等.对于平凡的可复制类型,包括char,相当于将它们设置为它们已经具有的确切值,这也没有可观察到的效果.

但是,如果获取的唯一方法s[2] == 'A'是通过内存操作,那么也可以使一个有效的参数,即你复制回你的Blob 内容不是以前构成的基础字节Blob.在这种情况下,从技术上讲,遗漏不会定义行为.

我强烈怀疑,特别是考虑到"对象是否持有类型的有效值T"注释,它是打算允许的.