0

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

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

然后我调用以下语句:

int c = TO_TI(1,2);

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

4

5 回答 5

4

给定a并且c您不能(通常)计算b,因为 a 和 b 是按位或在一起的,这是不可逆的(再次,通常)。考虑a=101b=1移位为 2。 Thenc=101与 if 相同b=0。没有简单的办法知道。

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

于 2013-05-30T11:17:34.947 回答
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;

但是, isb是未签名的,您必须非常小心不要对其进行签名扩展:

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

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

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

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

如果您将三个或更多值编码为同一个整数,那么事情会变得更加棘手。并提防int具有 64 位的系统。

规则:

  1. 了解您希望这些位做什么。
  2. 了解按位运算符对有符号和无符号值的作用。
  3. 仔细测试边界条件。

这就是发明位域的原因,您应该强烈考虑使用它们。

于 2013-05-30T13:01:39.927 回答
0

如果您确定 a 除了设置前 12 位之外没有其他位(然后 | 会破坏您在 b 上的信息),您可以使用 & 并右移来反转操作:

b = (c & ~a) >> 13

(~a 是 a 的按位否定)

编辑:实际上甚至不需要执行 & 因为通过右移最低 12 位将被移出......

于 2013-05-30T11:19:51.277 回答
0

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

b << 13乘以b2 13 = 8192。只要a最多 13 位长,即0 <= a < 8192,您可以通过取 8192 的模数来恢复它。您不需要b恢复a……反之亦然。

整个想法是a并且b应该很容易从 的结果中恢复TO_TI,因此首先要查看该宏定义周围的源代码,以找到应该反转该过程的宏。否则,c >> 13应该足以恢复b

应该注意的是,这两个数字都必须是正数,并且在所需的范围内才能正常工作。如果作者TO_TI从来没有提到a不能大于 8192,他们在方向盘上睡着了。

于 2013-05-30T11:36:33.233 回答
0

如果我正确理解了这个问题,给出的c来自

c = b<<13 | a; 

我们能找出原来的 ab吗?

这取决于

  • 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您可以检索ab,使用

a = c & 8191; // 2^13 - 1 or 0x1fff in hexa
b = c >> 13;  
于 2013-05-30T12:43:54.920 回答