6

让我们考虑以下代码:

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

char* s = reinterpret_cast<char*>(&blob);
s[2] = 'A';

假设 sizeof(double) 为 8,这段代码会触发未定义的行为吗?

4

2 回答 2

5

引用 N4140(大约 C++14):

3.9 类型 [basic.types]

2 对于普通可复制类型的任何对象(基类子对象除外)T,无论该对象是否拥有类型的有效值T,构成该对象的底层字节(1.7)都可以复制到char或的数组中unsigned char42char如果或数组的内容unsigned char被复制回对象,则该对象随后应保持其原始值。

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

3 对于任何可简单复制的类型T,如果两个指针T指向不同的T对象,obj1并且obj2既不是基类子对象obj1也不obj2是基类子对象,如果构成的基础字节(1.7)obj1被复制到obj2中,则43 obj2随后应保持与 相同的值obj1。[示例: ...]

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

原则上,这确实允许直接赋值,s[2]如果您采取s[2]间接要求赋值的位置等同于将所有其他内容复制Blob到一个数组中,该数组恰好除了第三个字节之外是按字节相同的,并将其复制到your Blob: 您没有分配给s[0],s[1]等。对于包括 在内的普通可复制类型char,这相当于将它们设置为它们已经拥有的确切值,这也没有明显的效果。

但是,如果获取的唯一方法s[2] == 'A'是通过内存操作,那么也可以提出一个有效的论点,即您复制回您Blob 的不是构成任何 previous 的基础字节Blob。在这种情况下,从技术上讲,行为将因遗漏而未定义。

我确实强烈怀疑,特别是考虑到“对象是否具有类型的有效值T”注释,它是被允许的。

于 2016-01-19T15:09:42.843 回答
0

标准的第 3.10 章似乎允许这种特定情况,假设“访问存储的值”是指“读取或写入”,这还不清楚。

3.10-10

如果程序尝试通过非下列类型之一的泛左值访问对象的存储值,则行为未定义

—(10.1)对象的动态类型,

—(10.2) 对象动态类型的 cv 限定版本,

—(10.3)与对象的动态类型类似(如 4.4 中定义)的类型,

—(10.4) 一种类型,它是与对象的动态类型相对应的有符号或无符号类型,

—(10.5) 有符号或无符号类型,对应于对象动态类型的 cv 限定版本,

—(10.6)聚合或联合类型,在其元素或非静态数据成员(递归地包括子聚合或包含联合的元素或非静态数据成员)中包括上述类型之一,

—(10.7) 一种类型,它是对象的动态类型的(可能是 cv 限定的)基类类型,

—(10.8) char 或 unsigned char 类型

于 2016-01-20T23:32:42.847 回答