提问人:ZeZNiQ 提问时间:10/8/2023 最后编辑:ZeZNiQ 更新时间:10/8/2023 访问量:95
打包结构体与联合体与枚举之间的区别
Difference between packing a struct vs union vs enum
问:
打包结构体、联合体和枚举有什么区别?
关于打包结构与打包联合,在 armv7l 上生成的汇编代码似乎有细微的差异(但在 x86_64 上没有):
#include <stdio.h>
struct uint18_struct {
unsigned int var:18;
} __attribute__((packed));
typedef struct uint18_struct uint18_struct_t;
union uint18_union {
unsigned int var:18;
} __attribute__((packed));
typedef union uint18_union uint18_union_t;
int main (void)
{
unsigned int bar = ~0U;
volatile uint18_struct_t foo = *((uint18_struct_t *) &bar);
printf ("max of uint18_t = %u\n", foo.var);
volatile uint18_union_t baz = *((uint18_union_t *) &bar);
printf ("max of bf_u18_t = %u\n", baz.var);
return 0;
}
为 foo 和 baz 生成的程序集:
volatile uint18_struct_t foo = *((uint18_struct_t *) &bar);
10358: f107 020c add.w r2, r7, #12
1035c: f107 0308 add.w r3, r7, #8
10360: 8811 ldrh r1, [r2, #0]
10362: 7892 ldrb r2, [r2, #2]
10364: 8019 strh r1, [r3, #0]
10366: 709a strb r2, [r3, #2]
volatile uint18_union_t baz = *((uint18_union_t *) &bar);
1037a: f107 020c add.w r2, r7, #12
1037e: 1d3b adds r3, r7, #4
10380: 8811 ldrh r1, [r2, #0]
10382: 7892 ldrb r2, [r2, #2]
10384: 8019 strh r1, [r3, #0]
10386: 709a strb r2, [r3, #2]
请注意生成的程序集(上图)中的前两行有何不同。ldrh
系统详细信息:
$ uname -a
Linux beaglebone 4.19.19-bone-rt-r21 #1stretch Wed Feb 6 11:01:34 UTC 2019 armv7l GNU/Linux
$ gcc --version
gcc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
我用的Cmdline:
$ gcc -g -O0 --save-temps main.c
您更愿意用哪一个来表示uint18_t类型 - 打包结构或打包联合?为什么?
编辑:想象一下,一个嵌入式控制器需要处理每个 9 位(但CHAR_BIT仍然是 8 位)的原始数据(因此需要 uint18_t),并且不提供 stdint.h、limits.h。
答:
0赞
chux - Reinstate Monica
#1
您希望哪一个来表示uint18_t类型 (?)
如
struct uint18_struct {
uint_least32_t var:18;
}
没有 .这种方式最便携。__attribute__((packed))
在 16 位系统上,希望它在位字段中接受 32 位 int 类型。int
否则,请考虑以下事项并自行处理子范围需求。
struct uint18_struct {
uint_least32_t var;
}
IMO,OP 还没有提出需要包装的好理由。也许一旦更大的问题被陈述出来,我们就可以努力解决真正的问题。
评论
0赞
ZeZNiQ
10/8/2023
“IMO,OP还没有提出需要包装的好理由。也许一旦更大的问题被陈述出来,我们就可以努力解决真正的问题。谢谢你的建议。刚刚添加。更大的问题是这个系统不会提供 stdint.h。因此,这些类型需要由我们自己定义。
0赞
chux - Reinstate Monica
10/9/2023
@ZeZNiQ 什么版本的 C? 自 C99 起可用。可以使用<stdint.h>
#if INT_MIN == -2147483648 typedef int my_int32_t #else ...
0赞
ZeZNiQ
10/9/2023
是的,这就是问题所在。这是一个裸机系统(想想在模拟器/FPGA 上验证的 ROM,还没有硅),我可能不得不自己定义这些标头。至少,我希望至少符合 C89,在这种情况下,limits.h 必须可用(以便您提出的INT_MIN方法可能有效),但不确定。这就引出了另一个问题 - 例如,有人可以在不提供 stdint.h 和 inttypes.h 的情况下声明 C99 兼容性,或者在不提供 limits.h 的情况下声明 C89 兼容性吗?
0赞
ZeZNiQ
10/9/2023
换句话说 - 有人可以声称部分符合特定版本的 C 标准吗?示例:符合 C99 且不带 stdint.h 和 inttypes.h,符合 C89 而不使用 limits.h 等。
1赞
ZeZNiQ
10/11/2023
__STDC__打印 1 和 __STDC_VERSION__ 错误,并显示“错误:__STDC_VERSION__未声明(首次使用此函数)”。
评论
uint18_t
char
char
struct
union
char
__attribute__((packed))