2015-11-27 37 views
0

以前,我有以下C代码,通过该C代码,我希望在演员制作后将变量'sample'的签名扩展为'signed short '变量'sample_unsigned'。向左旋转和向右旋转以用于标志扩展(带符号短)C

unsigned short sample_unsigned; 
signed short sample; 

sample = ((signed short) sample_unsigned << 4) >> 4; 

在二进制表示中,我期望'样本'有最重要的位重复4次。举例来说,如果:

sample_unsigned = 0x0800 (corresponding to "100000000000" in binary) 

我明白了“样本”应该结果是:

sample = 0xF800 (corresponding to "1111100000000000" in binary) 

然而,“样本”永远结束是一样的“sample_unsigned”,我不得不分割转让声明如下,哪些工作。为什么这个?

sample = ((signed short) sample_unsigned << 4); 
sample >>= 4; 

回答

0

您的方法不起作用。没有任何权利转移会保留标志。即使它只适用于16位int。对于> = 32位int,您必须手动将符号复制到高位,否则它只会来回移动相同的数据。一般来说,有符号值的位移很关键 - 有关详细信息,请参见[标准](http://port70.net/~nsz/c/c11/n1570.html#6.5.7)。有些星座会调用未定义的行为,最好避免使用它们,只使用无符号整数

对于大多数平台,以下工作,但它不一定是更慢(在16位int平台,它很可能甚至更快):

uint16_t usample; 
int16_t ssample; 

ssample = (int16_t)usample; 
if (ssample & 0x800) 
    ssample |= ~0xFFF; 

演员到int16_t是实现定义的;你的编译器应说明它是如何进行的(几乎。 ?)所有最近的实现都没有执行额外的操作,只需在生成的代码或编译器文档中进行验证即可 - 或依赖intX_t使用2s补码,这是标准保证的 - 与标准类型相反。

在32位平台上,可能存在内部指令进行签名扩展(例如ARM Cortex-M3/4 SBFX)。或者编译器提供一个内置函数。根据您的使用情况和速度要求,可能适合使用它们。

更新:

另一种方法是使用一个位域结构:

struct { 
    int16_t val : 12; // assuming 12 bit signed value like above 
} extender; 

extender.val = usample; 
ssample = extender.val; 

这可能会导致使用我上面提出的同样的汇编指令。

+0

我知道右移的符号扩展会产生未定义的行为。我正在研究64位Ubuntu 12.04,在检查了我的gcc文档后,我决定尝试一下。我需要做这种操作的原因是因为我从一个提供10位有符号值的硬件平台捕获数据,后来我需要将其另存为ASCII。正如你所建议的,我猜想使用'uint16_t'和'int16_t'应该是一个更稳定的解决方案。 –

+0

@CarlosCastro:我已经预料到了这种应用。我自己在嵌入式系统上使用它。只是不要依赖那个!上面的简单条件将不会在具有条件移动指令的平台上采用更多时钟(IIRC,x64确实提供了这样的功能,ARM明确做到这一点)。请注意,这是 - 像你问题中的代码 - 是12位有符号整数,而不是10位;所以你必须调整口罩!如果只是为了转换,可能会有更简单的技术。如果你可以节省内存空间,你甚至可以生成一个简单的查找表。 – Olaf

+0

@CarlosCastro:我稍微更新了答案。如果答案有帮助,请随时注册。如果您需要最佳性能,只需对变体进行基准测试(但要小心**您实际测试的基准) – Olaf

0

这是因为(signed short) sample_unsigned被自动转换为int如由于整数提升操作数。

sample = (signed short)((signed short) sample_unsigned << 4) >> 4; 

也可以工作。

+1

通过bitshift更改符号是未定义的行为。并且'signed short'仍然会被强制为'int'。 – Olaf

+1

而右移“签名”并不能保证无论如何都保留了标志(它甚至可以是UB)。 – Olaf

+0

内部(签名的短)可能不需要,只需在执行正确的转换之前进行签名即可。如前所述,这是特定环境,但对大多数二进制补码系统都有效。 – rcgldr