我想在 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%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
您始终可以将任何类型的对象作为字符数组(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("%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寄存器中的存储方式,这是另一回事。
之后,你会得到你的答案。
干杯