我想在C语言中用两种不同的数据类型访问一个单一的内存位置。
我想这样做。
我做了一个指针,并为它分配了64位的内存。然后我想通过使用以下两种方法访问该存储器 uint64_t
或 uint8_t[8]
.
使用 unsigned long long int
和 unsigned char
不对,因为 sizeof(unsigned char)==sizeof(uint8_t)
并不总是正确的。
我感觉循环和复制内存并不是真正需要的,我觉得这两种方式
uint64_t abc = { 0xdeadbeefcafe1337 }
和
uint8_t[8] xyz = { 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37 }
在记忆中看起来是一样的。
编辑:但是为什么呢?
我想在int上更方便地做简单的加法,我也想用类似数组的方式简单地访问该int值,一个字节时间。
你可以使用联合来实现
typedef union
{
uint64_t u64;
uint32_t u32[2];
uint16_t u16[4];
uint8_t u8[8];
}u64;
void foo(void)
{
u64 u;
u.u64 = 0xdeadbeefcafe1337ULL;
for(size_t i = 0; i < sizeof(u.u64); i++)
{
printf("byte %02d - 0x%hhX\n", i, u.u8[i]);
}
}
void foo(void)
{
u64 u;
u.u64 = 0xdeadbeefcafe1337ULL;
for(size_t i = 0; i < sizeof(u.u64); i++)
{
printf("byte %02d - 0x%hhX\n", i, u.u8[i]);
}
}
void bar(void)
{
u64 *u = malloc(sizeof(*u));
u -> u64 = 0x1337cafebeefdeadULL;
for(size_t i = 0; i < sizeof(*u); i++)
{
printf("byte %02d - 0x%hhX\n", i, u -> u8[i]);
}
free(u);
}
int main(void)
{
foo();
printf("-----------------------\n");
bar();
}
你总是可以以字符数组的形式访问任何类型的对象(char
, unsigned char
或 signed char
)和 uint8_t
在99.999%(100%?)的情况下,只是一个。unsigned char
.
即,你可以简单地做。
uint64_t abc = { 0xdeadbeefcafe1337 };
uint8_t *pabc = (uint8_t*)&abc[0];
然后用指针来检查或修改。abc
.
注意,严格的别名不允许你这样做。
uint64_t abc = { 0xdeadbeefcafe1337 };
uint32_t *pabc = (uint32_t*)&abc[0];
//^just this is ok but derefing this *pabc would violate strict aliasing
你需要一个 union
或 memcpy
,这实际上会得到优化,就像直接析出一样,但禁止析出是为了帮助编译器进行别名分析,这有助于更好的代码生成。
在相反的方向,即访问(甚至是一个正确对齐和正确大小的)声明的 uint8_t
阵列作为 uint64_t
也是不允许的,它与内存的外观无关,与别名分析有关。
好吧,从头开始,看看这段代码。
#include <stdio.h>
#include <stdint.h>
int main()
{
uint64_t abc = 0xdeadbeefcafe1337;
uint8_t xyz[8] = { 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37 };
printf("%x\n",xyz[0]);
printf("%x\n",((uint8_t*)&abc)[0]); //is the same of *(uint8_t*)&abc
return 0;
}
然后读一读 https:/en.wikipedia.orgwikiEndianness。. 注意不要混淆数据是如何存储在cpu寄存器中的,这是另外一回事。
之后,你会得到你的答案。
干杯