C 无法看到填充
我有一个这样的结构:C 无法看到填充,c,C,我有一个这样的结构: typedef struct la { bool b; union { uint16_t i; struct { uint8_t j; uint8_t k; }; }; } la_t; int main() { la_t a; a.b = 0x01c3; a.i = 0xa067; printf("%x", a.b); return 0; } 我知道在1字节的boo
typedef struct la {
bool b;
union {
uint16_t i;
struct {
uint8_t j;
uint8_t k;
};
};
} la_t;
int main()
{
la_t a;
a.b = 0x01c3;
a.i = 0xa067;
printf("%x", a.b);
return 0;
}
我知道在1字节的bool后面有一个填充,sizeof(la_t)是4。然而,即使我给bool分配了一个2字节的值,它也只返回01,第一个字节。如何访问/查看带有数据的填充字节?因为布尔类型就是这样工作的。它要么为真(
1
),要么为假(0
)
编译器将在布尔变量b
的赋值中,将所有非零值转换为true,将所有非零值转换为false(有关详细信息,请参阅小节)
“查看”结构中可能的填充的唯一方法是逐字节查看原始二进制形式。但是请注意,虽然允许填充,但它仍然作为实现细节保留了很多,并且可能的填充字节的内容是不确定的。任何读取数据(或更糟的是写入数据)的尝试都被视为UB。您不能合法地访问填充,但您可以通过考虑大小和偏移来证明其存在。请注意,分配给
bool
的任何非零值都会导致bool
保持1
akatrue
;只有指定的零值将以0
或false
结束
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
typedef struct la
{
bool b;
union
{
uint16_t i;
struct
{
uint8_t j;
uint8_t k;
};
};
} la_t;
int main(void)
{
la_t a;
a.b = 0x01c3;
printf("%x\n", a.b);
a.b = 0x0100;
printf("%x\n", a.b);
a.b = 0x0000;
printf("%x\n", a.b);
printf("Size of a.b = %zu\n", sizeof(a.b));
printf("Offset of a.b = %zu\n", offsetof(la_t, b));
printf("Size of a.i = %zu\n", sizeof(a.i));
printf("Offset of a.i = %zu\n", offsetof(la_t, i));
printf("Size of a = %zu\n", sizeof(a));
return 0;
}
如您所见,在布尔值b
和包含i
的匿名联合之间有1个字节的未请求空间(1个填充字节)
您可以将整个结构复制到一个字节数组(
memmove()
或memcpy()
)中,然后检查复制的字节值,但这几乎不合法,可能不可靠。与此相反,查看填充字节中内容的唯一方法是再次通过复制机制。请注意,对结构的其他成员的赋值可能会修改填充字节,也可能不会修改填充字节。您不能。它已被截断。您需要先memcpy该值,然后memcpy返回以读取它。或使用偏移量b
写入不是联合的一部分。通常,您不能通过访问成员本身来访问成员之间的填充。您需要使用char
指针直接访问结构的字节。尝试读取或写入填充字节不是未定义的行为。C中的对象由字节组成(C 2018 6.2.6 2)。明确允许您通过指向字符类型(6.2.6.4和6.3.2.3.7)的指针读取这些字节。这意味着您可以编写它们,因为这就是指定memcpy
工作的方式(7.24.2.1.2)。当修改结构成员时,填充字节确实采用未指定的值(6.2.6)。
1
1
0
Size of a.b = 1
Offset of a.b = 0
Size of a.i = 2
Offset of a.i = 2
Size of a = 4