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

时间:2016-08-28 13:18:35

标签: c struct bit-fields

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

我猜C编译器 HAS TO 会为按位操作生成额外的指令。因此,尽管数据大小减小,但代码大小也会增加。

任何熟悉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;
} 

2 个答案:

答案 0 :(得分: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

为了进行比较,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

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

答案 1 :(得分:2)

我记得,位字段的文档说这只是一个 建议编译器。实施是免费的 选择实际位或一些效率较低(空间)的实现。

比特字段实际上只是处理比特的一种方便的语法。

但事实证明,嵌入式编译器倾向于使用真正的位字段 因为使用位是嵌入式编程中非常常见的任务。
当然,如果需要,这必须与编译器一起记录 使用此功能。

关于汇编程序的复杂性,真正的位有意义 需要来自汇编程序的更多工作。