为什么 std::memcpy (作为类型双关的替代)不会导致未定义的行为?
Why does std::memcpy (as an alternative to type-punning) not cause undefined behaviour?
在寻找将 sizeof(double)
char
组合成 double
的方法时,我在几篇文章中读到,推荐使用 std::memcpy
的方法:
char bytes[sizeof(double)];
// fill array
double d;
std::memcpy(&d, bytes, sizeof(double));
但是,我想知道为什么进一步使用 d
可以定义行为。
如果它不是double
,而是一个复杂的class对象,访问它肯定也不会被定义,不是吗?那么,为什么 double
.
编辑: 为了让我的问题更清楚,我想明确我的目标:我想找到一种方法将几个 char
组合成一个 double
并进一步使用此 double,而不会导致未定义的行为。我不期望指定double
的值。无论如何我认为这是不可能的,因为标准甚至没有说明大小,更不用说 double
的位布局了。但是,我要求 d
有 一些 有效(即 'accessible')double
-value.
memcpy
to/from 字节缓冲区的标准中有一个特殊例外,因为如果没有明确定义的方法,某些操作将无法实现。
如果您从一种类型复制到字节,然后再复制到另一种类型,您肯定会得到未定义的行为。
Why does type-punning using std::memcpy not cause undefined behaviour?
因为语言是这么说的(最新草案):
[basic.types]
For any object (other than a potentially-overlapping subobject) of trivially copyable type T, whether or not the object holds a valid value of type T, the underlying bytes ([intro.memory]) making up the object can be copied into an array of char, unsigned char, or std::byte ([cstddef.syn]).
If the content of that array is copied back into the object, the object shall subsequently hold its original value.
但是请注意该规则的条件。您的代码可能具有未定义的行为,但如果复制的值最初是从另一个 double 复制的,或者实际上,如果该值可以从 double 复制。
If it was not a double, but a complex class object, accessing it surely would not be defined either, would it?
取决于您所说的复杂性。适用的条件在引用的规则中。
类型双关是被禁止的,因为它的想法是对 C++ 对象模型的嘲弄。一块内存存储一个对象,如果您开始访问它就像它存储了其他一些对象一样,那么这甚至意味着什么?如果你可以随便从内存中读取一个 int
,写入一个 float
,然后再从中读取一个 short
,那么它甚至意味着什么对象存在吗?
在普通可复制对象之间复制字节只是设置该对象值的另一种方式。实际上,这就是一个对象 "trivially copyable" 的逻辑含义:该对象的含义仅由构成其对象表示的字节序列定义(复杂对象不是这种情况)。但是保留了哪些记忆属于哪些对象的神圣性。没有"punning";到处都是复制数据。
在寻找将 sizeof(double)
char
组合成 double
的方法时,我在几篇文章中读到,推荐使用 std::memcpy
的方法:
char bytes[sizeof(double)];
// fill array
double d;
std::memcpy(&d, bytes, sizeof(double));
但是,我想知道为什么进一步使用 d
可以定义行为。
如果它不是double
,而是一个复杂的class对象,访问它肯定也不会被定义,不是吗?那么,为什么 double
.
编辑: 为了让我的问题更清楚,我想明确我的目标:我想找到一种方法将几个 char
组合成一个 double
并进一步使用此 double,而不会导致未定义的行为。我不期望指定double
的值。无论如何我认为这是不可能的,因为标准甚至没有说明大小,更不用说 double
的位布局了。但是,我要求 d
有 一些 有效(即 'accessible')double
-value.
memcpy
to/from 字节缓冲区的标准中有一个特殊例外,因为如果没有明确定义的方法,某些操作将无法实现。
如果您从一种类型复制到字节,然后再复制到另一种类型,您肯定会得到未定义的行为。
Why does type-punning using std::memcpy not cause undefined behaviour?
因为语言是这么说的(最新草案):
[basic.types]
For any object (other than a potentially-overlapping subobject) of trivially copyable type T, whether or not the object holds a valid value of type T, the underlying bytes ([intro.memory]) making up the object can be copied into an array of char, unsigned char, or std::byte ([cstddef.syn]). If the content of that array is copied back into the object, the object shall subsequently hold its original value.
但是请注意该规则的条件。您的代码可能具有未定义的行为,但如果复制的值最初是从另一个 double 复制的,或者实际上,如果该值可以从 double 复制。
If it was not a double, but a complex class object, accessing it surely would not be defined either, would it?
取决于您所说的复杂性。适用的条件在引用的规则中。
类型双关是被禁止的,因为它的想法是对 C++ 对象模型的嘲弄。一块内存存储一个对象,如果您开始访问它就像它存储了其他一些对象一样,那么这甚至意味着什么?如果你可以随便从内存中读取一个 int
,写入一个 float
,然后再从中读取一个 short
,那么它甚至意味着什么对象存在吗?
在普通可复制对象之间复制字节只是设置该对象值的另一种方式。实际上,这就是一个对象 "trivially copyable" 的逻辑含义:该对象的含义仅由构成其对象表示的字节序列定义(复杂对象不是这种情况)。但是保留了哪些记忆属于哪些对象的神圣性。没有"punning";到处都是复制数据。