输出中C结构组件中的前导0xff

输出中C结构组件中的前导0xff,c,struct,C,Struct,一些最奇怪的事情正在发生。遵循代码: #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(

一些最奇怪的事情正在发生。遵循代码:

#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);
  }
}
到现在为止,您可能已经发现了输出中的奇异性。实际上,在地址0x85a013到0x85a016的内存中没有“0xff”,每个字节也没有4个字节?!?!(我的意思是,这是合乎逻辑的吗?)。在我看来,这似乎是一个显示问题,但我无法找出原因或方式。

编辑

(字符*)
强制转换为
(无符号字符*)
。为了防止未定义的行为,不要尝试发布哨兵,而是使用struct size。我的版本:

#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]);
}
编辑

(字符*)
强制转换为
(无符号字符*)
。为了防止未定义的行为,不要尝试发布哨兵,而是使用struct size。我的版本:

#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]);
}
编辑

(字符*)
强制转换为
(无符号字符*)
。为了防止未定义的行为,不要尝试发布哨兵,而是使用struct size。我的版本:

#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]);
}
编辑

(字符*)
强制转换为
(无符号字符*)
。为了防止未定义的行为,不要尝试发布哨兵,而是使用struct size。我的版本:

#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]);
}

这是由有符号整数提升引起的。%x的
printf
说明符至少需要一个完整的
int

为了避免值大小的各种问题,变量参数函数,如
printf
将值至少转换为
int
double
大小


这意味着像0xab这样的
signed char
值被符号扩展为32位
0xffffffab

这是由有符号整数提升引起的。%x的
printf
说明符至少需要一个完整的
int

为了避免值大小的各种问题,变量参数函数,如
printf
将值至少转换为
int
double
大小


这意味着像0xab这样的
signed char
值被符号扩展为32位
0xffffffab

这是由有符号整数提升引起的。%x的
printf
说明符至少需要一个完整的
int

为了避免值大小的各种问题,变量参数函数,如
printf
将值至少转换为
int
double
大小


这意味着像0xab这样的
signed char
值被符号扩展为32位
0xffffffab

这是由有符号整数提升引起的。%x的
printf
说明符至少需要一个完整的
int

为了避免值大小的各种问题,变量参数函数,如
printf
将值至少转换为
int
double
大小


这意味着像0xab这样的
signed char
值被符号扩展为32位
0xffffffab
格式说明符
%x
需要
printf
中的
unsigned int
参数。仅当
int
值为非负值时,才允许在其位置使用
int
参数。如果该值为负值,则行为未定义

您正在为
%x
格式说明符传递一个
char
参数。变量
char
参数自动转换为
int
,并作为
int
传递。如果原始的
char
(以及由此产生的
int
)恰好具有负值,则该行为未定义。这显然就是你的情况。您的
ff
输出是使用
%x
格式说明符打印负
int
值的无效尝试的结果

您可以用几种不同的方法修复损坏的代码。例如,您可以将
printf
参数显式转换为
unsigned int
类型

printf("%p -> %x\n", (void *) m, (unsigned) *((char *)m));
这将消除未定义的行为,但很可能保持输出不变。现在,
ff
将显示为负值到
unsigned int
类型的模转换的[完美定义]结果

这个


这也是一种形式上有问题的做法。该语言不保证
结构
指针可以保留
字符*
指针的精确值。

格式说明符
%x
需要
printf
中的
无符号int
参数。仅当
int
值为非负值时,才允许在其位置使用
int
参数。如果该值为负值,则行为未定义

您正在为
%x
格式说明符传递一个
char
参数。变量
char
参数自动转换为
int
,并作为
int
传递。如果原始的
char
(以及由此产生的
int
)恰好具有负值,则该行为未定义。这显然就是你的情况。您的
ff
输出是使用
%x
格式说明符打印负
int
值的无效尝试的结果

您可以用几种不同的方法修复损坏的代码。例如,您可以将
printf
参数显式转换为
unsigned int
类型

printf("%p -> %x\n", (void *) m, (unsigned) *((char *)m));
这将消除未定义的行为,但很可能保持输出不变。现在,
ff
将显示为负值到
unsigned int
类型的模转换的[完美定义]结果

这个


这也是一种形式上有问题的做法。该语言不能保证
struct
指针可以保留
char*
指针的精确值。

格式说明符
%x