使用类型双关进行位获取。意外行为
Bit fetching with type punning. Unexpected behaviour
预期结果
该程序仅以其二进制表示形式打印 anyNum。
我们通过“前端弹出”值的第一位并将其发送到标准输出来实现这一点。
在 ≤32 次迭代后 i (=anyNum) 最终会降为零。循环结束。
问题
此代码的 v1 版本产生了预期的结果 (111...),
但是,在 v2 中,当我使用 mask 结构来获取第一位时,它就像最后一位被抓取一样工作(1000.. .).
也许不是最后一次?无论如何,第二版代码中发生了什么?
#include <iostream>
typedef struct{
unsigned b31: 1;
unsigned rest: 31;
} mask;
int main()
{
constexpr unsigned anyNum= -1; //0b111...
for (unsigned i= anyNum; i; i<<=1){
unsigned bit;
//bit= (i>>31); //v1
bit= ((mask*)&i)->b31; //v2 (unexpected behaviour)
std::cout <<bit;
}
}
环境
- IDE & 平台:https://replit.com/
- 平台:Linux-5.11.0-1029-gcp-x86_64-with-glibc2.27
- 机器:x86_64
- 编译命令:clang++-7 -pthread -std=c++17 -o main main.cpp
unsigned b31: 1;
是最低有效位。
Maybe not the last?
最后一个。
why
因为编译器选择这样做。顺序由编译器决定。
例如,在 GCC 上,位域中的位顺序由 BITS_BIG_ENDIAN 配置 选项控制。
x86 ABI 指定 bit-fields are allocated from right to left
.
what is happing in second version of the code?
未定义的行为,例如,代码无效。您不应该 期望 代码会做任何理智的事情。编译器恰好生成了从 i
.
打印最低有效位的代码
感谢@KamilCuk 我找到了答案。
在代码中做一点line-swap就可以修复它。
我用注释标记了 struct
(LTR) 的内存布局和 unsigned int
(RLT – Little endian) 的位布局。
没有考虑到他们是我的错误。
#include <iostream>
//struct uses left-to-right memory layout
typedef struct{
//I've swapped the next 2 lines as a correction.
unsigned rest: 31;
unsigned b31: 1; //NOW `b31` is the most significant bit.
} mask;
int main()
{
//unsigned is Little Endian on Linux-5.11.0-1029-gcp-x86_64-with-glibc2.27
//,which is right-to-left bit layout.
constexpr unsigned anyNum= -1; //0b111...
for (unsigned i= anyNum; i; i<<=1){
unsigned bit;
//bit= (i>>31); //v1
bit= ((mask*)&i)->b31; //v2 (NOW expected behaviour)
std::cout <<bit;
}
}
预期结果
该程序仅以其二进制表示形式打印 anyNum。
我们通过“前端弹出”值的第一位并将其发送到标准输出来实现这一点。
在 ≤32 次迭代后 i (=anyNum) 最终会降为零。循环结束。
问题
此代码的 v1 版本产生了预期的结果 (111...),
但是,在 v2 中,当我使用 mask 结构来获取第一位时,它就像最后一位被抓取一样工作(1000.. .).
也许不是最后一次?无论如何,第二版代码中发生了什么?
#include <iostream>
typedef struct{
unsigned b31: 1;
unsigned rest: 31;
} mask;
int main()
{
constexpr unsigned anyNum= -1; //0b111...
for (unsigned i= anyNum; i; i<<=1){
unsigned bit;
//bit= (i>>31); //v1
bit= ((mask*)&i)->b31; //v2 (unexpected behaviour)
std::cout <<bit;
}
}
环境
- IDE & 平台:https://replit.com/
- 平台:Linux-5.11.0-1029-gcp-x86_64-with-glibc2.27
- 机器:x86_64
- 编译命令:clang++-7 -pthread -std=c++17 -o main main.cpp
unsigned b31: 1;
是最低有效位。
Maybe not the last?
最后一个。
why
因为编译器选择这样做。顺序由编译器决定。
例如,在 GCC 上,位域中的位顺序由 BITS_BIG_ENDIAN 配置 选项控制。
x86 ABI 指定 bit-fields are allocated from right to left
.
what is happing in second version of the code?
未定义的行为,例如,代码无效。您不应该 期望 代码会做任何理智的事情。编译器恰好生成了从 i
.
感谢@KamilCuk 我找到了答案。
在代码中做一点line-swap就可以修复它。
我用注释标记了 struct
(LTR) 的内存布局和 unsigned int
(RLT – Little endian) 的位布局。
没有考虑到他们是我的错误。
#include <iostream>
//struct uses left-to-right memory layout
typedef struct{
//I've swapped the next 2 lines as a correction.
unsigned rest: 31;
unsigned b31: 1; //NOW `b31` is the most significant bit.
} mask;
int main()
{
//unsigned is Little Endian on Linux-5.11.0-1029-gcp-x86_64-with-glibc2.27
//,which is right-to-left bit layout.
constexpr unsigned anyNum= -1; //0b111...
for (unsigned i= anyNum; i; i<<=1){
unsigned bit;
//bit= (i>>31); //v1
bit= ((mask*)&i)->b31; //v2 (NOW expected behaviour)
std::cout <<bit;
}
}