C编译器如何处理位域?
How does C compiler handle bit-field?
以下bit field
示例代码来自here。它声称具有更好的存储效率。但是我想知道编译器是如何处理位域的?
我想 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;
}
So although the data size is reduced, the code size is increased.
总的来说,这是正确的:这是更紧凑的存储与更快的访问之间的权衡。
例如,这是我的编译器为您的位域示例中的 printf
语句生成的内容:
movq _dt@GOTPCREL(%rip), %rax
movzwl (%rax), %edx
movl %edx, %esi
andl , %esi ; -- extract the 5 bits representing day
shrl , %edx ; -+ extract the four bits for the month
andl , %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
当然,所有这些都是特定于编译器和平台的。
我记得,位字段的文档说这只是一个
编译器的建议。实施是免费的
选择实际位或一些效率较低的(space-wise)实现。
位域实际上只是一种用于处理位的便利语法。
但事实证明嵌入式编译器倾向于使用真实的位域,
因为使用位是嵌入式编程中非常常见的任务。
当然,如果需要的话,必须用编译器记录这一点
使用此功能。
关于汇编程序的复杂性,真正的位
是有道理的
需要汇编器做更多的工作。
以下bit field
示例代码来自here。它声称具有更好的存储效率。但是我想知道编译器是如何处理位域的?
我想 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;
}
So although the data size is reduced, the code size is increased.
总的来说,这是正确的:这是更紧凑的存储与更快的访问之间的权衡。
例如,这是我的编译器为您的位域示例中的 printf
语句生成的内容:
movq _dt@GOTPCREL(%rip), %rax
movzwl (%rax), %edx
movl %edx, %esi
andl , %esi ; -- extract the 5 bits representing day
shrl , %edx ; -+ extract the four bits for the month
andl , %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
当然,所有这些都是特定于编译器和平台的。
我记得,位字段的文档说这只是一个
编译器的建议。实施是免费的
选择实际位或一些效率较低的(space-wise)实现。
位域实际上只是一种用于处理位的便利语法。
但事实证明嵌入式编译器倾向于使用真实的位域,
因为使用位是嵌入式编程中非常常见的任务。
当然,如果需要的话,必须用编译器记录这一点
使用此功能。
关于汇编程序的复杂性,真正的位
是有道理的
需要汇编器做更多的工作。