如何在C语言中访问与两种不同数据类型(uint64_t/uint8_t[8])相同的内存地址?



我想在 C 编程语言中访问具有两种不同数据类型的单个内存位置。

这就是我希望它完成的方式:

我制作一个指针并为它分配 64 位内存。然后我想通过使用uint64_tuint8_t[8]来访问该内存。

使用unsigned long long intunsigned 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%hhXn", 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%hhXn", 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%hhXn", i, u -> u8[i]);
}
free(u);
}
int main(void)
{
foo();
printf("-----------------------n");
bar();
}

https://godbolt.org/z/hkoqFN

您始终可以将任何类型的对象作为字符数组(charunsigned charsigned 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

在那里,您需要一个unionmemcpy,它实际上会得到优化,就像直接取消引用一样,但禁止取消引用以帮助编译器进行别名分析,这有助于更好的代码生成。

反向,即访问(即使是正确对齐和适当大小(声明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("%xn",xyz[0]);
printf("%xn",((uint8_t*)&abc)[0]); //is the same of *(uint8_t*)&abc
return 0;
}

之后阅读 https://en.wikipedia.org/wiki/Endianness。当心不要混淆数据在CPU寄存器中的存储方式,这是另一回事。

之后,你会得到你的答案。

干杯

最新更新