使用memcpy将int复制到char数组中然后打印其成员:undefined behavior?

时间:2015-03-20 18:02:13

标签: c++ language-lawyer

请考虑以下代码:

int i = 1;
char c[sizeof (i)];
memcpy(c, &i, sizeof (i));
cout << static_cast<int>(c[0]);

请忽略这是否是好代码。我知道输出取决于系统的字节顺序。这只是一个学术问题。

这是代码:

  • 未定义的行为
  • 实施定义的行为
  • 定义明确的行为
  • 其他东西

3 个答案:

答案 0 :(得分:6)

语言并没有说这样做是立即未定义的行为。它只是说c[0] 的表示可能最终成为无效(陷阱)表示,在这种情况下,行为确实是未定义的。但是在c[0]不是陷阱表示的情况下,行为是实现定义的。

如果使用unsigned char数组,陷阱表示将变得不可能,行为将变为纯粹的实现定义。

答案 1 :(得分:3)

您正在寻找的规则是3.9p4:

  

类型为T的对象的对象表示形式是由N类型的对象占用的unsigned char T个对象的序列,其中N等于sizeof(T)。对象的值表示是一组位   保持类型T的值。对于简单的可复制类型,值表示是对象表示中的一组位,用于确定值,该值是实现定义的值集的一个离散元素。

因此,如果您使用unsigned char,您确实会获得实现定义的行为(任何符合要求的实现都必须保证您的行为是什么)。

通过char阅读也是合法的,但是未指定值。但是,您可以保证使用不合格的char将保留该值(因此裸char不能有陷阱表示或填充位),根据3.9p2:

  

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

(&#34;未指定&#34;值比&#34;实现定义的&#34;值稍弱 - 语义相同,但不需要平台来记录值是什么。)

答案 2 :(得分:1)

显然是实施定义的行为。

int的内部表示不是由标准定义的(实现可以选择little或big endian或其他任何东西),因此它不能很好地定义行为:结果允许在不同的体系结构上有所不同。

在一个已定义的系统(体系结构和C编译器以及(最终)配置)上,行为是完全确定的:在一个大端,你将获得一个1,在一个小端上为0.所以它是实现定义行为