我正在尝试了解如何调试已序列化为字节数组的数据。该代码显示了解决方案试验失败的问题。
我想要实现的是获得仅12345678
的整个数组成员78
的打印。
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main()
{
uint32_t words[2] = {0x12345678, 0x87654321};
char * struct_array = &words;
printf("%x \n", *struct_array); // 78 prints a lsb byte from the first array member
printf("%lx \n", *struct_array); // 78 assuming it would print more than a single byte
//Perhaps it's printing a single byte because of the char pointer.
printf("%x \n", (uint32_t) *struct_array); // 78
printf("%lx \n", (uint32_t) *struct_array); // 78
// Nope
}
答案 0 :(得分:2)
struct_array
的类型为char*
,i。即指向char的指针。 *struct_array
然后解引用单个char
(单个字节),因此只查看words
占用的内存中的第一个字节。你得到0x78,因为显然你的机器是一个小端,所以数据以逆字节顺序存储。将char
转换回uint32_t
不会改变任何内容 - 值为0x78,它适合32位整数,因此它保持为0x78。
如果你想获得整个价值,你需要阅读整个价值,i。即取消引用指向uint32_t
的指针,这意味着您需要在解除引用之前转换指针:
*(uint32_t*)struct_array
答案 1 :(得分:2)
此:
char * struct_array = &words;
将struct_array
变为指向char
的指针。取消引用会为您提供char
,您无法通过投射来改变之后的。
您当然可以在解除引用之前强制转换指针(但风险未定义的行为):
printf("%x\n", *(uint32_t *) struct_array);
当然,最好使用正确的反序列化代码,而不是试图通过指针解除引用欺骗来强制它。如果你有一堆你知道的字节代表一个更大的数字,那就把它放在一起吧。
要扩展最后一点,如果这是一个实际的字节数组:
const uint8_t data[] = { 0x78, 0x56, 0x34, 0x12 };
并且您希望将它们重新组合成一个32位无符号整数,假设您执行的是小端存储:
const uint32_t x = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
printf("x de-serialized into 0x%08x\n", x);
这会打印x de-serialized into 0x12345678
,所有这些都不会违反任何内容。 :)
答案 2 :(得分:1)
//expected it would print more than a single byte
这种期望是错误的。取消引用已经完成,当时struct_array
的类型为char *
。然后(提升)的值用作转换说明符的参数。
要强调的是,所提供的参数类型和转换说明符并不像您预期的那样内部相关,程序员的工作就是让两者保持一致。
如果希望缓冲区生成源类型的原始值,则需要使用强制转换将指针变为实际类型,然后取消引用以获取该值。在取消引用之后,演员在这里毫无意义。
注意事项:您只能将指针强制转换回原始类型或兼容类型,而不仅仅是“任何”其他类型,这会破坏严格的别名。