user-0 提问: Union如何让成员尾部对齐?

回复:
user: user-1
content: 仅供参考：#include <stdio.h> #define field_offset(s,f) (int)(&(((struct s *)(0))->f)) struct AD  { int a; char b[13]; double c;}; #pragma pack(push) #pragma pack(1) struct A1  { int a; char b[13]; double c;}; #pragma pack(2) struct A2  { int a; char b[13]; double c;}; #pragma pack(4) struct A4  { int a; char b[13]; double c;}; #pragma pack(8) struct A8  { int a; char b[13]; double c;}; #pragma pack(16) struct A16 { int a; char b[13]; double c;}; #pragma pack(pop) int main() {     printf("AD.a %d\n",field_offset(AD,a));     printf("AD.b %d\n",field_offset(AD,b));     printf("AD.c %d\n",field_offset(AD,c));     printf("\n");     printf("A1.a %d\n",field_offset(A1,a));     printf("A1.b %d\n",field_offset(A1,b));     printf("A1.c %d\n",field_offset(A1,c));     printf("\n");     printf("A2.a %d\n",field_offset(A2,a));     printf("A2.b %d\n",field_offset(A2,b));     printf("A2.c %d\n",field_offset(A2,c));     printf("\n");     printf("A4.a %d\n",field_offset(A4,a));     printf("A4.b %d\n",field_offset(A4,b));     printf("A4.c %d\n",field_offset(A4,c));     printf("\n");     printf("A8.a %d\n",field_offset(A8,a));     printf("A8.b %d\n",field_offset(A8,b));     printf("A8.c %d\n",field_offset(A8,c));     printf("\n");     printf("A16.a %d\n",field_offset(A16,a));     printf("A16.b %d\n",field_offset(A16,b));     printf("A16.c %d\n",field_offset(A16,c));     printf("\n");     return 0; } //AD.a 0 //AD.b 4 //AD.c 24 // //A1.a 0 //A1.b 4 //A1.c 17 // //A2.a 0 //A2.b 4 //A2.c 18 // //A4.a 0 //A4.b 4 //A4.c 20 // //A8.a 0 //A8.b 4 //A8.c 24 // //A16.a 0 //A16.b 4 //A16.c 24 // //

user: user-0
content: 引用 10 楼 vnvlyp 的回复:尾部对齐这是个什么需求。。能不能讲一讲我倒觉得很有意思 这在大部分机器上（little-endian）岂不是高位对齐 主要是处理通信协议,  一个通信数据流,一个字节一个字节的接收的,发送方是先发头再发尾的,  可能有多个格式(struct)的数据,  所以是想把这个多个格式组成一个尾部对齐的Union, 然后每收到一个字节就向前推移动一个字节, 并检查各struct标记校验

user: user-2
content: 尾部对齐这是个什么需求。。能不能讲一讲我倒觉得很有意思 这在大部分机器上（little-endian）岂不是高位对齐

user: user-3
content: 编译器不是会自动优化的吗

user: user-4
content: typedef long int T4;        /*根据具体的环境自行定义*/ typedef long long int T8;   /*根据具体的环境自行定义*/  /*静态断言_Static_assert需要你的编译器支持C11，当然也可以不用这一行*/ _Static_assert (sizeof (T8) == 8 && sizeof (T4) == 4, "ERROR DATA TYPE.");  union u {     T8 b8;     struct {T4 t, b4;};/*匿名结构的成员直接成为联合的成员，下同*/     struct {char c [sizeof (T8) - 1]; char b1;}; } __attribute__ ((packed));/*packed来自编译器提供的特性*/  int main (void) {     union u u;     u.b8 = 0x42000000FFFFFFFF;     /* Some use of u */     u.b1 = 'x';     /* Some use of u */     u.b4 = 8;     /* Some use of u */ }

user: user-5
content: 哦。。。b4 也要偏位。。。 一样  套个 struct

user: user-5
content: 再套个 struct 填位   #include <stdio.h> #include <math.h>  union u1 { 	long b4; 	long long b8; 	struct { 		char _t[7]; 		char b1; 	}; }  int main(int argc, char *argv[]) { 	union u1 *p = NULL; 	printf("%x %x", p, &p->b1); // 0   7 }

user: user-4
content: # include <stdio.h>  int main (void) {     union u     {         long long b8;         struct {long c; long b4};         struct {char b [7]; char b1;};     } __attribute__ ((packed));      union u u;     u.b8 = 0x42000000FFFFFFFF;     printf ("%ld\n", u.b4);     printf ("%c", u.b1); }

user: user-4
content: 因为long long和long对于不同的实现来说大小也不同，而且，如何使一个结构内部无填充，不同的实现也有不同的方法，所以，以下代码仅为示例，抛砖引玉，没有通用性： union u {      long long b8;      struct {long pad1; long b4};      struct {char pad2 [7]; char b1;};  } __attribute__ ((packed));

user: user-6
content: 我能想到的workaround： union u1 {   long b4[2];   long long b8;   char b1[8]; }; b4[1] b1[7] 应该是你想要的。

user: user-0
content: 引用 1 楼 sholber 的回复:不明白你在说什么。 union u {long b4; long long b8; char b1;} u; 你的意思是，假定sizeof (long long) == 8；sizeof (long) == 4，u起始的线性地址是0x00000020，那么： b4的线性地址是0x00000024；b8的线性地址是0x00000020而b1的线性地址是0x00000027吗？ 如果是这种要求，不可能办到，否则C标准就得大面积修改了。 对,我就是想这样,正常情况各成员都是0x00000020开始,但现在是想倒过来放 地址                         成员 0x00000020:        ------------------------------------------------------------------------------------------------------------------ 0x00000021:        ↑ 0x00000022:        || 0x00000023:       b8 0x00000024:        占8个字节          ------------                0x00000025:        ||                              ↑ 0x00000026:        ↓                            b4占4个字节 0x00000027:        ________________↓___________________ b1占一个字节______________________

user: user-4
content: 不明白你在说什么。 union u {long b4; long long b8; char b1;} u; 你的意思是，假定sizeof (long long) == 8；sizeof (long) == 4，u起始的线性地址是0x00000020，那么： b4的线性地址是0x00000024；b8的线性地址是0x00000020而b1的线性地址是0x00000027吗？ 如果是这种要求，不可能办到，否则C标准就得大面积修改了。