发生了一些最奇怪的事情。遵循代码:
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
struct s
{
char a;
char b;
char c;
unsigned int d;
unsigned int e;
}__attribute__((packed));
int main(void)
{
struct s *m = (void *)malloc(sizeof (struct s));
assert(m);
m->a=0x33;
m->b=0x33;
m->c=0x33;
m->d=0xabcdefab;
m->e=0x12345678;
*(char *)(m + 1) = 0;
while (*((char*)m))
{
printf("%p -> %x\n", m, *((char *)m));
m = (struct s *)((char*) m + 1);
}
}
这是输出:
0x85a010 -> 33
0x85a011 -> 33
0x85a012 -> 33
0x85a013 -> ffffffab
0x85a014 -> ffffffef
0x85a015 -> ffffffcd
0x85a016 -> ffffffab
0x85a017 -> 78
0x85a018 -> 56
0x85a019 -> 34
0x85a01a -> 12
到目前为止,您可能已经发现了输出中的瑕疵。的确,没有&#39; 0xff&#39;在内存地址0x85a013到0x85a016,每个字节也不是4个字节?!?! (我的意思是,这是否合乎逻辑?)。在我看来,这是一个显示问题,但我无法弄清楚为什么或如何。
答案 0 :(得分:1)
修改强>
将(char *)
演员表更改为(unsigned char *)
。并且为了防止未定义的行为,不要尝试发布标记,但使用结构大小。我的版本:
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#pragma pack(push, 1)
struct s
{
char a;
char b;
char c;
unsigned int d;
unsigned int e;
};
#pragma pack(pop)
int main(void)
{
int i;
unsigned char *cptr;
struct s *m = malloc(sizeof (struct s));
assert(m);
m->a=0x33;
m->b=0x33;
m->c=0x33;
m->d=0xabcdefab;
m->e=0x12345678;
cptr = (unsigned char*)m;
for (i=0; i<sizeof(struct s); i++)
printf("%p -> %02x\n", (void*)(cptr+i), cptr[i]);
}
节目输出:
001C2DD0 -> 33
001C2DD1 -> 33
001C2DD2 -> 33
001C2DD3 -> ab
001C2DD4 -> ef
001C2DD5 -> cd
001C2DD6 -> ab
001C2DD7 -> 78
001C2DD8 -> 56
001C2DD9 -> 34
001C2DDA -> 12
答案 1 :(得分:1)
这是由签名整数提升引起的。 %x的printf
说明符至少需要一个完整大小的int
值。
为了避免值大小的各种问题,可变参数函数(如printf
)将值转换为至少int
和double
大小。
这意味着像{0x}这样的signed char
值被符号扩展为32位0xffffffab
答案 2 :(得分:1)
格式说明符%x
在unsigned int
中需要printf
个参数。仅当int
值为非负数时,才允许在其位置使用int
参数。如果值为负,则行为未定义。
您正在为char
格式说明符传递%x
参数。可变参数char
参数自动转换为int
并传递为int
。如果原始char
(因此结果int
)恰好具有负值,则行为未定义。这显然是你的情况。您的ff
输出是使用int
格式说明符无效尝试打印否定%x
值的结果。
您可以通过多种不同方式修复损坏的代码。例如,您可以将printf
参数显式转换为unsigned int
类型
printf("%p -> %x\n", (void *) m, (unsigned) *((char *)m));
这将消除未定义的行为,但很可能会保持输出不变。现在,ff
将显示为将负值模数转换为unsigned int
类型的[完美定义]结果。
此
m = (struct s *)((char*) m + 1);
也是一个正式可疑的做法。该语言不保证struct
指针可以保留char *
指针的确切值。