我有两个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)什么是最好/最快的方式?
谢谢!
答案 0 :(得分:7)
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;
}
答案 1 :(得分:3)
$ 5.8 / 1状态 - “操作数应为整数或枚举类型,并执行整数提升。结果的类型是提升左操作数的类型。如果右操作数为负数,则表示行为未定义大于或等于提升左操作数的位数。“
因此,尝试将c1强制转换为unsigned int,然后将其与C2进行按位OR运算。还将输出作为unsigned int返回。 chars被提升为int但我们希望成为'unsigned int'
答案 2 :(得分:2)
原因是在执行按位OR之前c2
首先被提升为int
,这会导致符号扩展(假设char已签名且可以保留负值):
char x1 = -2; // 1111 1110
char x2 = -3; // 1111 1101
short int si = stitch(c1, c2); // 1111 1111 1111 1101
x2
提升为int
的表示(至少)1字节满1
,因此它会覆盖您之前向上移位的x1
的零位。您可以先转换为unsigned char
。使用两个补码表示,不会更改最低字节中的位模式。虽然不是绝对必要,但您也可以将c1
强制转换为unsigned char
以保持一致性(如果短2个字节长,则c1
符号扩展超出这2个字节无关紧要)
short int stitch(char c1, char c2) {
return ((unsigned char)c1 << 8) | (unsigned char)c2;
}
答案 3 :(得分:1)
移位/或方法一旦修复,就更清晰,因为它不依赖于字节顺序。
除此之外,由于存储到转发(STLF)问题,许多现代CPU上的union方法可能会更慢。您正在将值写入内存,然后将其作为不同的数据类型读回。如果发生这种情况,许多CPU无法快速将数据发送到负载。负载需要等到存储完全完成(退役),将其数据写入L1缓存。
在没有桶形移位器的非常旧的CPU上(移位8需要8次操作)并且通过简单的有序执行,例如68000,union方法可能更快。
答案 4 :(得分:-1)
你不应该使用联盟。你永远不应该同时使用联合字段。如果工会有成员A和成员B,那么你必须考虑A和B是无关的。那是因为编译器可以随意在任何地方添加填充(除了在struct的前面)。另一个问题是字节顺序(小/大端)。
// EDIT 上面的“联合规则”有例外,您可以同时使用这些成员,这些成员在前面并具有相同的布局。即
union {
struct {
char c;
int i;
short s;
} A;
struct {
char c;
int i;
char c1;
char c2;
} B;
};
A.c和A.i可与B.c和B.i同时使用