如何在C中获得左移位值?

时间:2013-05-30 11:10:26

标签: c macros

我有一个问题,定义了以下marco:

TO_TI(a, b) ((b)<<13|(a))

然后我称之为以下声明:

int c = TO_TI(1,2);

然后我将结果c传递给一个函数,在这个函数中,如何基于值c并输入一个计算b的值?

5 个答案:

答案 0 :(得分:4)

鉴于ac,您不能(通常)计算b,因为a和b一起按位OR,并且这是不可逆的(一般情况下) 。考虑a=101b=1,班次为2.然后c=101b=0相同。简单的没有办法知道。

如果您使用XOR而不是OR,或者您有更多信息,例如对所涉及值范围的限制,我们可能会取得更多进展。

答案 1 :(得分:1)

将多个整数打包成一个更大的整数通常是有用的,编写宏是一个很好的方法来实现它(尽管我更喜欢内联函数)。

关键是你必须知道自己在做什么!如果您不能正确理解基础位操作,或者至少遵守规则,那么您将无法获得所放置的内容。

只要a是一个使用不超过12位的正整数,您的TO_TI宏就能正常工作。 b不得超过20位数据(假设32位字)。

如果a未签名,则可以像这样提取:

unsigned int a = c & 0xFFF;

但是,如果a已签名,那么您必须“签署 - 扩展”该值,如下所示:

int a = ((int)c << 20) >> 20;

同样,如果b已签名,则必须进行符号扩展,但这更容易:

int b = (int)c >> 12;

但是,b是未签名的,你必须非常小心来签名扩展它:

unsigned int b = (unsigned int)c >> 12;

最后,如果您想允许a具有负值,那么您必须像这样定义宏:

#define TO_TI(a, b) ((b)<<13|((a)&0xFFF))

(否则a的符号位将覆盖b。)

如果您将三个或更多值编码到同一个整数中,那么事情会变得更加毛茸茸。并注意int具有64位的系统。

规则:

  1. 了解你想要的东西。
  2. 了解按位运算符对有符号和无符号值的作用。
  3. 仔细测试边界条件。
  4. 这就是发明位域的原因,你应该强烈考虑使用它们。

答案 2 :(得分:0)

如果你确定a除了设置的前12位之外没有其中一位(那么|会破坏你在b上的信息)你可以使用&amp;并向右移动以反转操作:

b = (c & ~a) >> 13

(~a是a的按位否定)

编辑:确实甚至不需要做&amp;因为通过右移,最低的12位将被移出......

答案 3 :(得分:0)

TO_TI遵循一个习惯用法将多个值打包到位域中。 (它也在向你眨眼。)

b << 13b乘以2 13 = 8192.只要a长度最多为13位,即0 <= a < 8192,您可以通过将模数设为8192来恢复它。您不需要b来恢复a ...反之亦然。

整个想法是ab应该很容易从TO_TI的结果中恢复,所以首先要看看围绕该宏定义的来源找到应该反转过程的宏。否则,c >> 13应足以恢复b

应该注意的是,这两个数字必须是正数且在要求的范围内才能发挥作用。如果TO_TI的作者从未提及a不能大于8192,那么他们就会睡着了。

答案 4 :(得分:0)

如果我正确理解了这个问题,那么 c 是由

产生的
c = b<<13 | a; 

我们能找到原来的 a b 吗?

取决于

  • a 的长度(位数):除上述问题外,如果 a msb(最高有效位)为2 ^ 13或更多, |操作会影响 b 在班次(b << 13)之后的位置,因此您无法知道第13位的 c 值是否为来自原始 b ,或来自 a

  • b 的长度:移位13位将 b 乘以2 ^ 13(8192),如果 b 是最初足够大,在移位后它可能溢出 c ,即结果不适合 c 大小(长度),并且 b 检索从下面的方法将小于原来的 b

所以,如果 a 小于8192(2 ^ 13)但是正数(否则其msb将达到 b 移位) b 向左移位13位不会溢出 c 您可以检索 a b ,使用

a = c & 8191; // 2^13 - 1 or 0x1fff in hexa
b = c >> 13;