我有一个问题,定义了以下marco:
TO_TI(a, b) ((b)<<13|(a))
然后我称之为以下声明:
int c = TO_TI(1,2);
然后我将结果c
传递给一个函数,在这个函数中,如何基于值c并输入一个计算b
的值?
答案 0 :(得分:4)
鉴于a
和c
,您不能(通常)计算b
,因为a和b一起按位OR,并且这是不可逆的(一般情况下) 。考虑a=101
和b=1
,班次为2.然后c=101
与b=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位的系统。
规则:
这就是发明位域的原因,你应该强烈考虑使用它们。
答案 2 :(得分:0)
如果你确定a除了设置的前12位之外没有其中一位(那么|会破坏你在b上的信息)你可以使用&amp;并向右移动以反转操作:
b = (c & ~a) >> 13
(~a是a的按位否定)
编辑:确实甚至不需要做&amp;因为通过右移,最低的12位将被移出......
答案 3 :(得分:0)
宏TO_TI
遵循一个习惯用法将多个值打包到位域中。 (它也在向你眨眼。)
b << 13
将b
乘以2 13 = 8192.只要a
长度最多为13位,即0 <= a < 8192
,您可以通过将模数设为8192来恢复它。您不需要b
来恢复a
...反之亦然。
整个想法是a
和b
应该很容易从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;