C编译器如何处理位字段?

smw*_*dia 3 c struct bit-fields

以下bit field示例代码来自此处.它声称存储效率更高.但我想知道编译器如何处理位字段?

我猜的C编译器必须生成逐位操作额外的指令.因此,尽管数据大小减小,但代码大小也会增加.

任何熟悉C编译器的人都可以解释一下吗?

#include <stdio.h>

// A space optimized representation of date
struct date
{
   // d has value between 1 and 31, so 5 bits
   // are sufficient
   unsigned int d: 5;

   // m has value between 1 and 12, so 4 bits
   // are sufficient
   unsigned int m: 4;

   unsigned int y;
};

int main()
{
   printf("Size of date is %d bytes\n", sizeof(struct date));
   struct date dt = {31, 12, 2014};
   printf("Date is %d/%d/%d", dt.d, dt.m, dt.y);
   return 0;
} 
Run Code Online (Sandbox Code Playgroud)

NPE*_*NPE 5

因此,尽管数据大小减小,但代码大小也会增加.

一般来说,这是正确的:它是更紧凑的存储与更快的访问之间的权衡.

例如,这是我的编译器为printf你的位域示例中的语句生成的:

    movq    _dt@GOTPCREL(%rip), %rax
    movzwl  (%rax), %edx
    movl    %edx, %esi
    andl    $31, %esi     ; -- extract the 5 bits representing day
    shrl    $5, %edx      ; -+ extract the four bits for the month
    andl    $15, %edx     ; /
    movl    4(%rax), %ecx ; -- year doesn't require any bit manipulation
    leaq    L_.str.1(%rip), %rdi
    xorl    %eax, %eax
    callq   _printf
Run Code Online (Sandbox Code Playgroud)

为了比较,相同的代码何时date是简单的struct:

    movq    _dt@GOTPCREL(%rip), %rax
    movl    (%rax), %esi  ; -- day
    movl    4(%rax), %edx ; -- month
    movl    8(%rax), %ecx ; -- year
    leaq    L_.str.1(%rip), %rdi
    xorl    %eax, %eax
    callq   _printf
Run Code Online (Sandbox Code Playgroud)

所有这些当然都是编译器和平台特定的.