C union 关键字

nxdong July 30, 2022 [cpp] #cpp

C union 关键字的一些用法

基本原则

  1. union中可以定义多个成员,union的大小由最大的成员的大小决定。
  2. union成员共享同一块大小的内存,一次只能使用其中的一个成员。
  3. 对某一个成员赋值,会覆盖其他成员的值
  4. 联合体union的存放顺序是所有成员都从低地址开始存放的。

代码

union.c 文件如下:

#include <stdio.h>
#include <string.h>

typedef union
{
    char str[100];
    char c;
    int i;
    float f;
} MyUnion;

void print_union(MyUnion *u)
{
    printf("MyUnion size: %d c:%c i:%d f:%f str:%s\n", sizeof(*u), u->c, u->i, u->f, u->str);
}

int main(int argc, char **argv)
{
    MyUnion d;
    d.c = 'H';
    print_union(&d);

    d.i = 49;
    print_union(&d);

    d.f = 3.14;
    print_union(&d);
    strcpy(d.str, "Hello world!");
    print_union(&d);

    printf("MyUnion Size       : %d \n", sizeof(MyUnion));
    printf("sizeof MyUnion     : %d \n", sizeof((MyUnion){{0}}));
    printf("sizeof MyUnion.str : %d \n", sizeof((MyUnion){{0}}).str);
    printf("sizeof MyUnion.c   : %d \n", sizeof((MyUnion){{0}}).c);
    printf("sizeof MyUnion.i   : %d \n", sizeof((MyUnion){{0}}).i);
    printf("sizeof MyUnion.f   : %d \n", sizeof((MyUnion){{0}}).f);
    return 0;
}

编译运行

gcc union.c 
MyUnion size: 100 c:H i:72 f:0.000000 str:H
MyUnion size: 100 c:1 i:49 f:0.000000 str:1
MyUnion size: 100 c:� i:1078523331 f:3.140000 str:��H@
MyUnion size: 100 c:H i:1819043144 f:1143139122437582505939828736.000000 str:Hello world!
MyUnion Size       : 100 
sizeof MyUnion     : 100 
sizeof MyUnion.str : 100 
sizeof MyUnion.c   : 1 
sizeof MyUnion.i   : 4 
sizeof MyUnion.f   : 4 

附注

sizeof((MyUnion){{0}}).f 的操作会不会有性能损失?

不会。sizeof 是编译期间求值的。

The operator sizeof produces the required memory storage space of its operand when the code is compiled

参考: https://en.wikipedia.org/wiki/Sizeof

union2.c 如下

#include <stdio.h>
#include <string.h>

typedef union
{
    int f;
} MyUnion;

int main(int argc, char **argv)
{
    MyUnion d;
    d.f = 3;
    int a = sizeof d;
    int b = sizeof d.f;
    int c = sizeof((MyUnion){0}).f;

    return 0;
}

编译对应的汇编代码:

gcc -S -masm=intel union2.c -o union2.s

union2.s的内容如下:

  .file  "union2.c"
  .intel_syntax noprefix
  .text
  .globl  main
  .type  main, @function
main:
.LFB0:
  .cfi_startproc
  push  rbp
  .cfi_def_cfa_offset 16
  .cfi_offset 6, -16
  mov  rbp, rsp
  .cfi_def_cfa_register 6
  mov  DWORD PTR -20[rbp], edi
  mov  QWORD PTR -32[rbp], rsi
  mov  DWORD PTR -16[rbp], 3
  mov  DWORD PTR -12[rbp], 4
  mov  DWORD PTR -8[rbp], 4
  mov  DWORD PTR -4[rbp], 4
  mov  eax, 0
  pop  rbp
  .cfi_def_cfa 7, 8
  ret
  .cfi_endproc
.LFE0:
  .size  main, .-main
  .ident  "GCC: (GNU) 11.1.0"
  .section  .note.GNU-stack,"",@progbits

可以观察到汇编代码中是常量。

也可以通过[godbolt](https://godbolt.org/) 在线观察汇编对应情况

参考资料

https://en.wikipedia.org/wiki/Sizeof