unsigned char tab[4] = 14;
如果我打印为单个字节...
printf("tab[1] : %u\n", tab[0]); // output: 0
printf("tab[2] : %u\n", tab[1]); // output: 0
printf("tab[3] : %u\n", tab[2]); // output: 0
printf("tab[4] : %u\n", tab[3]); // output: 14
如果我打印为整数...
unsigned int *fourbyte;
fourbyte = *((unsigned int *)tab);
printf("fourbyte : %u\n", fourbyte); // output: 234881024
我的二进制输出是:00001110 00000000 00000000 00000000,这是我想要的数据,但是按此顺序tab [3] tab [2] tab [1] tab [0]。 对此有何解释,为什么unsigned int指针指向最后一个字节而不是第一个字节?
答案 0 :(得分:1)
这里的正确答案是,您不应该期望任何关系,顺序或其他方式。除并集外,C标准未定义不同类型的对象可以重叠的线性地址空间。在许多体系结构/编译器-工具链组合中,经常会发生这些巧合,但您永远不要依赖它们。通过将指针强制转换为合适的标量类型会产生一个与其他相同类型的数字可比的数字,这实际上意味着数字是任何特定的内存地址。
所以:
int* p;
int z = 3;
int* pz = &z;
size_t cookie = (size_t)pz;
p = (int*)cookie;
printf("%d", *p); // Prints 3.
之所以行之有效,是因为该标准说,当cookie
是从要转换的指针的相同类型派生时,它必须能够工作。转换为任何其他类型都是未定义的行为。指针不代表内存,它们抽象地引用了“存储”。它们仅是对对象或NULL的引用,并且标准定义了指向同一对象的指针的行为方式,以及如何将它们转换为标量值并再次返回。
给出:
char array[5] = "five";
该标准说&(array[0]) < &(array[1])
和那个(&(array[0])) + 1) == &(array[1])
,但是对于array
中的元素在内存中的排序方式它是静音的。编译器作者可以自由使用他们认为适合目标体系结构的任何机器代码和内存布局。
就联合而言,它在存储中提供了对象的一些重叠,该标准仅表示其每个字段都必须针对其类型进行适当对齐,但是关于它们的几乎所有其他内容都由实现定义。关键条款是6.2.6.1 p7:
当值存储在联合类型的对象的成员中时,与该成员不对应但与其他成员对应的对象表示形式的字节采用未指定的值。
所有这些的要旨是C标准定义了一个抽象机。编译器根据您的代码为该计算机生成特定于体系结构的仿真。您无法通过简单的经验手段来理解C抽象机,因为实现细节会渗入数据集中。您必须将您的观察限制为与抽象有关的观察。因此,请避免未定义的行为,并非常了解实现定义的行为。
答案 1 :(得分:0)
您的示例代码在Little-Endian计算机上运行。该术语表示整数的“第一个字节”包含最低有效位。相比之下,Big-Endian计算机将最高有效位存储在第一个字节中。
编辑后添加:您已经证明这是不安全的,因为它依赖于未定义的行为来“直接访问”内存。有更安全的示范here