[英]C++: Union vs Bitwise operators
我有两个char
,我想把它们“按”拼接在一起。
例如:
char c1 = 11; // 0000 1011
char c2 = 5; // 0000 0101
short int si = stitch(c1, c2); // 0000 1011 0000 0101
所以,我首先尝试的是按位运算符:
short int stitch(char c1, char c2)
{
return (c1 << 8) | c2;
}
但这不起作用:我得到一个short
等于c2
...... (1)为什么?
(但是: c1
和c2
在我的真实应用程序中是负数...也许这是问题的一部分?)
所以,我的第二个解决方案是使用union
:
union stUnion
{
struct
{
char c1;
char c2;
}
short int si;
}
short int stitch(char c1, char c2)
{
stUnion u;
u.c1 = c1;
u.c2 = c2;
return u.si;
}
这就像我想要的...... 我想
(2)什么是最好/最快的方式?
谢谢!
union
方法最多是实现定义的(实际上,它将非常可靠地工作,但si
的格式取决于平台的字节顺序)。
正如您所怀疑的那样,按位方式的问题是负数。 负数由前导1的链表示。 所以-5例如是
1111 1011
如果将其转换为int
或甚至unsigned int
,它就会变为
1111 1111 1111 … 1111 1011
当应用OR时,所有那些1将淹没左移数据。
要解决这个问题,请将char
为unsigned char
,然后转换为int
(以防止溢出,甚至出现溢出的可能性):
short int stitch(char c1, char c2)
{
return ( (int) (unsigned char) c1 << 8) | (unsigned char) c2;
}
或者,如果您可以自由更改参数的类型,并且可以包含<cstdint>
,
uint16_t stitch( uint8_t c1, uint8_t c2)
{
return ( (int) c1 << 8 ) | c2;
}
$ 5.8 / 1状态 - “操作数应为整数或枚举类型,并执行整数提升。结果的类型是提升左操作数的类型。如果右操作数为负,或者等于或等于,则行为未定义以升级的左操作数的位数为长度。“
因此,尝试将c1类型转换为unsigned int,然后对C2进行按位OR运算。 还将输出作为unsigned int返回。 chars被提升为int但我们希望成为'unsigned int'
原因是在执行按位OR之前首先将c2
提升为int
,这会导致符号扩展(假设char已签名且可以保存负值):
char x1 = -2; // 1111 1110
char x2 = -3; // 1111 1101
short int si = stitch(c1, c2); // 1111 1111 1111 1101
提升为int
的x2
的表示是(至少)1字节满1
,因此它会覆盖先前向上移位的x1
的零位。 您可以先转换为unsigned char
。 使用两个补码表示,不会更改最低字节中的位模式。 虽然不是绝对必要,但为了保持一致性,你也可以将c1
为unsigned char
(如果short是2个字节长,那么c1
符号扩展超出这2个字节并不重要)
short int stitch(char c1, char c2) {
return ((unsigned char)c1 << 8) | (unsigned char)c2;
}
移位/或方法一旦修复,就更清晰,因为它不依赖于字节排序。
除此之外,由于存储到负载转发(STLF)问题,许多现代CPU上的union方法可能会更慢。 您正在将值写入内存,然后将其作为不同的数据类型读回。 如果发生这种情况,许多CPU无法快速将数据发送到负载。 负载需要等到存储完全完成(退役),将其数据写入L1缓存。
在没有桶形移位器的非常旧的CPU(移位8需要8次操作)和简单的有序执行(例如68000)上,union方法可能更快。
你不应该使用联盟。 你永远不应该同时使用联合字段。 如果工会有成员A和成员B,那么你必须考虑A和B是无关的。 那是因为编译器可以随意在任何地方添加填充(除了在struct的前面)。 另一个问题是字节顺序(小/大端)。
//编辑上面的“联合规则”有例外,您可以同时使用这些成员,这些成员位于前端并具有相同的布局。 即
union {
struct {
char c;
int i;
short s;
} A;
struct {
char c;
int i;
char c1;
char c2;
} B;
};
Ac和Ai可与Bc和Bi同时使用
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.