请考虑以下代码:
int i = 1;
char c[sizeof (i)];
memcpy(c, &i, sizeof (i));
cout << static_cast<int>(c[0]);
请忽略这是否是好代码。我知道输出取决于系统的字节顺序。这只是一个学术问题。
这是代码:
答案 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)都可以是复制到char
或unsigned char
的数组中。如果将char
或unsigned char
数组的内容复制回对象,则该对象应随后保持其原始值。
(&#34;未指定&#34;值比&#34;实现定义的&#34;值稍弱 - 语义相同,但不需要平台来记录值是什么。)
答案 2 :(得分:1)
显然是实施定义的行为。
int的内部表示不是由标准定义的(实现可以选择little或big endian或其他任何东西),因此它不能很好地定义行为:结果允许在不同的体系结构上有所不同。
在一个已定义的系统(体系结构和C编译器以及(最终)配置)上,行为是完全确定的:在一个大端,你将获得一个1,在一个小端上为0.所以它是实现定义行为