C++ 在C+中,将位字段结构转换为int+;
我有一个具有相同类型成员的结构。我正在尝试将其转换为C++ 在C+中,将位字段结构转换为int+;,c++,c++11,visual-c++,bit-fields,reinterpret-cast,C++,C++11,Visual C++,Bit Fields,Reinterpret Cast,我有一个具有相同类型成员的结构。我正在尝试将其转换为uint8\t类型。我可以这样做,但看不到输出。请告诉我哪里出了问题。我也知道还有其他的方法吗?我尝试这样做是因为我想习惯static\u cast和reinterpret\u cast 代码如下: int main() { struct xs{ bool x :1 ; bool y :1; bool z :1; uint8_t num :5; } zs;
uint8\t
类型。我可以这样做,但看不到输出。请告诉我哪里出了问题。我也知道还有其他的方法吗?我尝试这样做是因为我想习惯static\u cast
和reinterpret\u cast
代码如下:
int main()
{
struct xs{
bool x :1 ;
bool y :1;
bool z :1;
uint8_t num :5;
} zs;
uint8_t* P = static_cast<uint8_t*>(static_cast<void*>(&zs));
cout << *P << endl;
return 0;
}
intmain()
{
结构xs{
boolx:1;
booly:1;
boolz:1;
uint8_t num:5;
}zs;
uint8_t*P=静态_cast(静态_cast(&zs));
库特
通过指向对象类型以外的类型的指针访问对象是一种未定义的行为。它适用于大多数编译器,但从技术上讲,您的程序可以做任何它想做的事情
假设我们没有遇到1中提到的问题,我猜uint8_t是char的别名,所以cout会将char放在控制台上。
您没有初始化正在检查的内存,因此它可以是0。值为0的字符不会在控制台中打印任何“可观察”的内容,请查看ascii表。例如,尝试用50填充结构
这里有两件事需要解决。首先,正如一些人指出的那样,您不能以这种方式访问对象。如果您想正确构造uint8,您需要读取结构中的变量并进行一些位移位,例如:
uint8_t value = 0;
value |= (zs.x ? 1 << 7 : 0);
value |= (zs.y ? 1 << 6 : 0);
value |= (zs.z ? 1 << 5 : 0);
value |= zs.num;
uint8\u t值=0;
值|=(zs.x?1这里有很多问题:
您似乎认为x
、y
和z
将全部打包到单个uint_8
中。事实并非如此。“然后,编译器可以将相同类型的相邻声明位字段打包成更少的字。”
“sizeof(bool)
的值由实现定义,可能与1不同”,因此您的xs
将由实现定义,但肯定不等同于sizeof(uint_8)
因为xs
与uint_8
不“相似”,根据重新解释的行为,cast
未定义
最后,您看不到任何内容的原因是,无论实现定义的值在*P
处,当被cout
视为char
代码的一个可能解决方法是使用以下定义:
constexpr uint8_t X = 0B1000'0000;
constexpr uint8_t Y = 0B0100'0000;
constexpr uint8_t Z = 0B0010'0000;
constexpr uint8_t NUM = 0B0001'1111;
uint8_t zs;
然后,如果为zs
分配了一些值,则可以执行以下功能以输出前一个位字段:
cout << ((zs & X) != 0) << endl;
cout << ((zs & Y) != 0) << endl;
cout << ((zs & Z) != 0) << endl;
cout << (zs & NUM) << endl;
一个uint8\u t
实际上是一个无符号字符,因此将被打印为一些ascii字符,很可能不是一个可见字符。将其转换为其他整数类型。但请记住你在做什么(将一个类型视为它不是的类型)太可怕了,无法保证会发生什么。@BoBTFish尝试使用char-type仍然没有输出@BoBTFish说这是未定义的行为。struct xs
的大小和布局是由实现定义的,在大小上可能不是uint8\u t
。即使是这样,您的强制转换也被定义为不起作用。See在中指出:只是一个警告:也许“习惯”重新解释强制转换不是最好的主意。重新解释强制转换用于特殊情况,不应该经常使用,实际上它们是红色信号,表明正在发生奇怪的事情。“你没有初始化正在检查的内存,所以它可以是0”不,它将是未初始化的垃圾。我不认为它是UB。对于类型为char*
、unsigned char*
和std::byte*
@JonathanWakely的指针有一个例外。从技术上讲,根据标准its垃圾,它可以是0:P。我最初想到的是编译器的“扩展”int只能在调试模式下初始化为零。我想我在某个地方读到过visual studio这样做的内容?但我可能在这里大错特错。所以我让它打开到“它可以是0”。@Jens你是对的。但是uint8\u不总是(!)别名字符、无符号字符或字节?@phön你说得对。std::uint8_t
可以是正好是8位的任何类型,因此即使char_位==8
也可以是其他类型。char
也可以大于8位(这会使sizeof
有趣,因为它是sizeof(char)
的倍数),在这种情况下,std::uint8\u t
没有什么不同。我在现实生活中从未见过这种情况。谢谢你,你在“1”中描述的正是我想要的。我现在尝试实现int*P=static\u cast(static\u cast(&zs));它是有效的。但是,如果我定义x为真,那么输出为1,但是如果我定义y为真,那么输出为2。它的工作顺序是这样的。谢谢。我想我知道它在8421规则中工作,因为根据位位置它给了我一个整数。但是当试图在那里使用char而不是int时,y不起作用。你有什么理由告诉我们吗ed#为常数定义
?这似乎是初学者的问题,所以我不会展示一些你不应该使用的东西。@Mandeep我恐怕至少我不明白你在说什么。8421是什么?你在哪里使用字符而不是int?代码中没有int
。@Jen没有特别的原因。const uint8\t x=0B1000'0000
的工作原理与#define
的工作原理相同
cout << ((zs & X) != 0) << endl;
cout << ((zs & Y) != 0) << endl;
cout << ((zs & Z) != 0) << endl;
cout << (zs & NUM) << endl;