我有一个短片,instr看起来像这样:
1110xxx111111111
Run Code Online (Sandbox Code Playgroud)
我需要拔出0-9位,我这样做(instr & 0x1FF).然后将该数量存储在新的短期中.问题是,当这种情况发生时,它变得0x0000000111111111不0x1111111111111111喜欢我想要的.我怎样才能解决这个问题?谢谢!
这是代码:
short instr = state->mem[state->pc];
unsigned int reg = instr >> 9 & 7; // 0b111
state->regs[reg] = state->pc + (instr & 0x1FF);
Run Code Online (Sandbox Code Playgroud)
这是一个读取汇编的模拟器.state是机器,regs[]是寄存器,pc是当前指令的地址mem[].
如果最后9位表示正数,则可以正常,但如果它们表示-1,则将其存储为全1,这由我的代码解释为正值.
Ben*_*son 23
假设一个短是16位:
你可以手动完成: (instr & 0x1FF) | ((instr & 0x100) ? 0xFE00 : 0).这将测试符号位(您保留的最高位0x100),并在符号位置位时设置其上方的所有位.您可以通过调整掩码将此扩展为5位0x1F,0x10并将0xFFE0其作为低5位,第5位本身和所有位5-16.
或者你可以找一些借口将这些位分配给一个有符号的短的上部并将它们向下移动(在这个过程中得到一个符号扩展):short x = (instr & 0x1FF) << 7; x >>= 7; 后者实际上可能最终在汇编中更直接而且不会涉及一个分支.如果instr是签订这可以在一个单一的表达来完成: (instr & 0x1FF) << 7 >> 7.由于这已经消除了高位,因此简化为instr << 7 >> 7.将7替换为11乘以5位(16-5).
nim*_*odm 12
*无需分支*
请参阅http://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend以获取非常有用的位黑客列表.具体而言,扩展数字的符号非常简单:
/* generate the sign bit mask. 'b' is the extracted number of bits */
int m = 1U << (b - 1);
/* Transform a 'b' bits unsigned number 'x' into a signed number 'r' */
int r = (x ^ m) - m;
Run Code Online (Sandbox Code Playgroud)
x = x & ((1U << b) - 1);在使用上述过程之前,如果它们不是零(),您可能需要清除'x'的最高位.
如果在编译时知道位数'b'(例如,在你的情况下是5位),那么甚至有一个更简单的解决方案(如果处理器支持它并且编译器足够聪明,这可能会触发特定的符号扩展指令):
struct {signed int x:5;} s;
r = s.x = x;
Run Code Online (Sandbox Code Playgroud)