#include <assert.h>
#include <limits.h>
unsigned ab_to_c(signed short a, signed short b) {
assert(SHRT_MAX == 32767);
assert(UINT_MAX == 4294967295);
// unsigned int c = a << 16 | b; fails as `b` get sign extended before the `|`.
// *1u insures the shift of `a` is done as `unsigned` to avoid UB
// of shifting into the sign bit.
unsigned c = (a*1u << 16) | (b & 0xFFFF);
return c;
}
void c_to_ab(unsigned c, signed short *a, signed short *b) {
*a = c >> 16;
*b = c & 0xFFFF;
}
4 E1 << E2的结果是E1左移E2位位置;空出的比特会以零填满。如果E1是不带负数号的型别,则结果的值为E1 x 2E2,以结果型别中可表示的最大值再加1为模约简。如果E1是带负数号的型别,且值为非负数,且E1 x 2E2可在结果型别中表示,那么这就是结果值;否则,行为未定义。 您可以将signed short明确转换为unsigned short,以取得可预测的行为。
#include <stdio.h>
int main()
{
signed short a, b;
a = -16;
b = 340;
unsigned int c = (unsigned short)a << 16 | (unsigned short)b;
signed short ar, br;
ar = c >> 16;
br = c & 0xFFFF;
printf("ar: %hd, br: %hd\n", ar, br);
}
5条答案
按热度按时间u4dcyp6a1#
楼主差点就猜对了
q5lcpyga2#
由于
a
具有负值,导致未定义的行为。
来自C99标准(重点矿井):
6.5.7按位移位运算符
4
E1 << E2
的结果是E1
左移E2
位位置;空出的比特会以零填满。如果E1
是不带负数号的型别,则结果的值为E1
x2
E2
,以结果型别中可表示的最大值再加1为模约简。如果E1
是带负数号的型别,且值为非负数,且E1
x2
E2
可在结果型别中表示,那么这就是结果值;否则,行为未定义。您可以将
signed short
明确转换为unsigned short
,以取得可预测的行为。输出量:
nbewdwxp3#
这真的很奇怪,我已经编译了你的代码,它对我来说很有效,也许这是一个未定义的行为,我不确定,但是如果我是你,我会添加强制转换,以明确避免一些位丢失,这可能是或可能不是由滥用二进制补码或编译器自动强制转换引起的....
在我看来,发生的事情可能是你把所有的位移出一个...试试这个
jk9hmnmh4#
这是因为你使用了一个无符号整型数,它通常是32位,而一个带负数号的短整型数通常是16位。当你把一个带负数的短整型数放入一个无符号整型数中时,这个“负”位会被解释为正数的一部分。所以你在无符号整型数中得到的是一个非常不同的数字。
存储两个正数可以解决这个问题....但您可能需要存储一个负数。
dced5bon5#
不确定这种方式是否有利于便携性或其他,但我使用...
我喜欢我做的方式,因为它提供了很多准备,可以在许多方面应用,即02x32,04x16,08x08等。我是新的C,所以请随时批评我的代码和方式做...谢谢