如何处理位字段中的单位(布尔)成员?
How are single-bit (boolean) members in bit fields handled?
当我请求或设置按位 struct
/class
的单位成员时,编译器会进行位移吗?例如,给定此 struct
:
struct {
unsigned char thing : 4;
unsigned char flag1 : 1;
unsigned char flag2 : 1;
unsigned char reserved : 2;
}
...编译器是否意识到不需要移位?也就是说,编译器是不是这样做的:
uchar request_flag1() const {
uchar temp = data & 0x40; //0100 0000 - get the 7th bit
return temp >> 7; //0000 0001 - return the shifted value
}
void set_flag1(uchar v) {
data &= 0x191; //1011 1111 - clear the 7th bit
data |= v << 7; //0v00 0000 - set the 7th bit to shifted value
}
还是这个?
bool request_flag1() const {
return data & 0x40; //0100 0000 - simply check whether the 7th bit is set
}
void set_flag1(bool v) {
if(v) data |= 0x40; //0100 0000 - simply set the 7th bit
else data &= 0x191; //1011 1111 - simply clear the 7th bit
}
我想后者会明显更快,因为它是操作次数的一半。
如果后者 为 true,我是否必须将位域成员声明为 bool
类型才能获得此优势?
编译器会将您的位操作转换为完成任务所需的任何一系列 bitwise-and/or/not 操作。
例如
s.flag1 = 1;
会变成
s = s | 00000010;
^^^^^^-----stuff
^----flag1
^---flag2
并且分配的实际值将取决于您正在编译的特定 CPU 的 bit/byte 顺序。
您的问题无法笼统回答。每个编译器都可以自由决定如何实现位域。不能保证是高位在前还是低位在前。这可能取决于系统的端点,但也不能保证。所以用union转换bit-field肯定是不可移植的!
编译器可以生成的代码取决于编译器以及它必须为其创建代码的cpu。例如,如果你想测试和设置一些位,一些 cpu 架构支持一个 opcode/instruction 完全用于该用途。另一个 cpu 可能只能检查 lsb,所以它必须移动它 n 次才能捕捉到你想要的位。其他一些 cpu 可能与 and/or 组合一起使用。
简单回答:视情况而定:-)
但几乎可以保证现代编译器将尽最大努力生成可以在选定 cpu 上完成工作的最小或快速代码。
如果您真的想知道您的编译器生成了什么,只需查看生成的程序集即可。
在 linux 您可以使用:
objdump -S a.out
这使您的程序集和源代码混合在一起。
当我请求或设置按位 struct
/class
的单位成员时,编译器会进行位移吗?例如,给定此 struct
:
struct {
unsigned char thing : 4;
unsigned char flag1 : 1;
unsigned char flag2 : 1;
unsigned char reserved : 2;
}
...编译器是否意识到不需要移位?也就是说,编译器是不是这样做的:
uchar request_flag1() const {
uchar temp = data & 0x40; //0100 0000 - get the 7th bit
return temp >> 7; //0000 0001 - return the shifted value
}
void set_flag1(uchar v) {
data &= 0x191; //1011 1111 - clear the 7th bit
data |= v << 7; //0v00 0000 - set the 7th bit to shifted value
}
还是这个?
bool request_flag1() const {
return data & 0x40; //0100 0000 - simply check whether the 7th bit is set
}
void set_flag1(bool v) {
if(v) data |= 0x40; //0100 0000 - simply set the 7th bit
else data &= 0x191; //1011 1111 - simply clear the 7th bit
}
我想后者会明显更快,因为它是操作次数的一半。
如果后者 为 true,我是否必须将位域成员声明为 bool
类型才能获得此优势?
编译器会将您的位操作转换为完成任务所需的任何一系列 bitwise-and/or/not 操作。
例如
s.flag1 = 1;
会变成
s = s | 00000010;
^^^^^^-----stuff
^----flag1
^---flag2
并且分配的实际值将取决于您正在编译的特定 CPU 的 bit/byte 顺序。
您的问题无法笼统回答。每个编译器都可以自由决定如何实现位域。不能保证是高位在前还是低位在前。这可能取决于系统的端点,但也不能保证。所以用union转换bit-field肯定是不可移植的!
编译器可以生成的代码取决于编译器以及它必须为其创建代码的cpu。例如,如果你想测试和设置一些位,一些 cpu 架构支持一个 opcode/instruction 完全用于该用途。另一个 cpu 可能只能检查 lsb,所以它必须移动它 n 次才能捕捉到你想要的位。其他一些 cpu 可能与 and/or 组合一起使用。
简单回答:视情况而定:-)
但几乎可以保证现代编译器将尽最大努力生成可以在选定 cpu 上完成工作的最小或快速代码。
如果您真的想知道您的编译器生成了什么,只需查看生成的程序集即可。
在 linux 您可以使用:
objdump -S a.out
这使您的程序集和源代码混合在一起。