为什么使用移位的此交换宏不适用于负数? [英] Why doesn't this swap macro using shifts not work for negative numbers?

查看:90
本文介绍了为什么使用移位的此交换宏不适用于负数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在内置库中找到了一些我需要扩展的代码.

I found some code in a built in library that I have and need to extend.

但它似乎已损坏:

#define BSWAP16(__x)    ((((__x) >> 8) | ((__x) << 8)))

与以下功能不同:

__builtin_bswap16()

该程序证明了这一点.

#include <stdio.h>

#define BSWAP16(__x)    ((((__x) >> 8) | ((__x) << 8)))

int main(int argc, char* argv[])
{
    unsigned short a = (unsigned short)BSWAP16(0xff00);
    unsigned short b = __builtin_bswap16(0xff00);
    short c = (short)BSWAP16(-8);
    short d = __builtin_bswap16(-8);

    printf("a=%04x, b=%04x, c=%04x, d=%04x\n", a,b,c,d);
    return 0;
}

输出:

a=00ff, b=00ff, c=ffffffff, d=fffff8ff

我不想回答告诉我应该使用endian.h或__builtin_bswap16.在此平台/编译器配置的内部库使用的目标平台上,我正在触发此默认代码,该代码默认使用上述宏.

I'm not wanting answers telling me I should use endian.h or __builtin_bswap16. On the target platform used by this in-house library on this platform/compiler configuration, I'm triggering this default code that is defaulting to using the above macro.

所以我的问题是.为什么对负数不起作用?

So my question is. Why doesn't it work for negative numbers?

如果我将-8表示为0xfff8的短值,那么它将起作用.

If I represent -8 as a short value of 0xfff8 it works.

所以我想这与内部转换为int有关.

So I'm guessing it has something to do with internal conversion to int.

如何解决此宏以使其正常工作?

How do I fix this macro to work properly?

推荐答案

从草案C99标准部分6.5.7 按位移位运算符说,( 强调我的前进):

It is undefined behavior to left shift a negative number, from the draft C99 standard section 6.5.7 Bitwise shift operators which says (emphasis mine going forward):

E1的结果<< E2是E1左移E2位的位置;空出 位填充零.如果E1具有无符号类型,则的值 结果是E1´2E2,比最大值减少了模一 在结果类型中可以表示. 如果E1具有签名类型,并且 非负值,并且在结果类型中可以表示E1´2E2, 那就是结果值; 否则,该行为是 未定义.

The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. If E1 has an unsigned type, the value of the result is E1 ´ 2E2, reduced modulo one more than the maximum value representable in the result type. If E1 has a signed type and nonnegative value, and E1 ´ 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.

因此,-8左移的结果是不可预测的.强制转换为 unsigned short 应该可以解决以下问题:

So the result of the left shift of -8 is unpredictable. Casting to unsigned short should fix the issue:

BSWAP16((unsigned short)-8)

-8是一个整数常量( literal ),由于它没有后缀,因此它是一个 int ,因为 int 可以取价值.假设32-bit int 和二进制补码将具有以下值:

-8 is an integer constant(literal) and since it does not have a suffix will be an int since int can take on it's value. Assuming 32-bit int and twos complement will have have the following value:

 FFFFFFF8

广播到 unsigned short 将删除不需要的高位.强制转换为 unsigned int 不会有帮助,因为它将保留较高的位.

casting to unsigned short will remove the unwanted higher bits. Casting to unsigned int won't help since it will preserve the higher bits.

还定义了右移负数:

E1 >> E2的结果是E1右移E2位的位置.如果E1有 无符号类型,或者如果E1具有带符号类型和非负值, 结果的值是E1/的商的整数部分 2E2. 如果E1具有带符号的类型和负值,则结果值 是实现定义的.

The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 / 2E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined.

这篇关于为什么使用移位的此交换宏不适用于负数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆