【问题标题】:memcpy from one type to another type. How do we access the destination afterwards?memcpy 从一种类型到另一种类型。之后我们如何访问目的地?
【发布时间】:2016-09-20 13:12:52
【问题描述】:
uint32_t u32 = 0;
uint16_t u16[2];
static_assert(sizeof(u32) == sizeof(u16), "");
memcpy(u16, &u32, sizeof(u32)); // defined?
// if defined, how to we access the data from here on?

这是定义的行为吗?如果是这样,我们可以使用什么类型的指针来访问memcpy之后的目标数据?

我们必须使用uint16_t*,因为它适合u16声明类型吗?

或者我们必须使用uint32_t*,因为源数据的类型(memcpy复制的源数据)是uint_32

(个人对 C++11/C++14 感兴趣。但讨论 C 等相关语言也会很有趣。)

【问题讨论】:

  • 现在可以了 :-)(我忘记了 & 和另一个错字)
  • 您是否正在尝试找出您的 CPU 的字节序?
  • @Bob__,我目前没有特别的应用。但我会说,根据答案,它可能会允许我在未来在某些项目中考虑进行一些积极的优化。
  • @Bob__,也许这可以更好地传达我希望确认的内容:“给定一个声明为 X 类型的变量,它总是是合法的通过X 类型的指针访问它。并且memcpy 进入这样的变量总是很酷并且不会更改类型,只要您坚持使用可以推断位模式的简单类型(整数,指针, ...) 并且在陷阱表示或对齐方面没有问题”.

标签: c++11 strict-aliasing


【解决方案1】:

这是定义的行为[u]r 吗?

是的。 memcpying 到一个 pod 是明确定义的,并且您确保大小是正确的。

我们必须使用uint16_t*,因为它适合u16的声明类型吗?

是的,当然。 u16 是一个由两个 uint16_ts 组成的数组,因此必须这样访问它。通过uint32_t* 访问它将是严格别名规则未定义的行为。

源类型是什么并不重要。重要的是你有一个uint16_t[2] 类型的对象。


另一方面,这个

uint32_t p;
new (&p) uint16_t(42);
std::cout << p;

是未定义的行为,因为现在有一个不同类型的对象,其生命周期从&amp;p 开始,我们通过错误的类型访问它。

【讨论】:

  • 让我担心的一点是,C 标准中有一些句子向我暗示类型是uint32_t,例如“[类型变为 ] ...从中复制值的对象...“。我手头没有任何标准文件,我所能做的就是复制并粘贴我在网上找到的东西 - 我在这里找到了这句话:stackoverflow.com/questions/30970251/…
  • @AaronMcDaid C++ 不是 C。
  • 在某些情况下,除非 C++ 明确声明它 C。 (见 user2079303 的回答)。
  • 这比reinterpret_cast 有什么优势吗?我认为两者都应该导致实现定义的结果。
  • @AaronMcDaid 我应该澄清你和我引用的 C 标准中的 6.5/6 不适用于 C++。 7.24 和其他一些明确说明的章节确实适用于 C++。
【解决方案2】:

C++ 标准委托给 C 标准:

头文件&lt;cstring&gt;的内容和含义与C标准库头文件&lt;string.h&gt;相同。

C 标准规定:

7.24.1/3 对于本子条款中的所有函数,每个字符都应被解释为好像它具有 unsigned char 类型(因此每个可能的对象表示都是有效的并且具有不同的值)。

所以,回答您的问题:是的,行为已定义。

是的,uint16_t* 是合适的,因为 uint16_t 是对象的类型。


不,来源的类型无关紧要。

C++ 标准没有指定没有声明类型的对象或它的行为方式。我将其解释为有效类型是为没有声明类型的对象定义的实现。

即使在 C 语言中,在这种情况下源也不重要。您关注的 C 标准(草案,N1570)的更完整版本的引用,强调我的:

6.5/6 [...] 如果使用 memcpy 或 memmove 将值复制到没有声明类型的对象中,或者复制为字符类型的数组,则该访问的修改对象和不修改该值的后续访问是从中复制该值的对象的有效类型(如果有的话)。 [...]

此规则不适用,因为u16 中的对象确实具有声明的类型

【讨论】:

  • 一个小的跟进:一个对象的'声明类型',如果它有一个,永远不会改变?一个对象永远不会失去或获得“声明的类型”?但是“有效类型”在某些情况下会发生变化吗?
  • @AaronMcDaid 声明的类型不会改变。如果 object 已声明类型,那么它也是有效类型 - 而且它不会改变。如果没有声明类型,则可以获取或更改有效类型。
  • 我现在认为,如果此处有关“已声明”和“有效”类型的这些 cmets 在每个答案的开始。
  • @AaronMcDaid:我知道“声明类型”和“对象”没有与所有现有编译器行为一致的定义。如果函数接收到 foo* 类型的指针,编译器可能会将其目标视为声明类型为 foo,而不管它是否真的这样做。
猜你喜欢
  • 1970-01-01
  • 2010-09-19
  • 2021-04-11
  • 1970-01-01
  • 2011-05-30
  • 1970-01-01
  • 1970-01-01
  • 2011-10-02
  • 1970-01-01
相关资源
最近更新 更多