int to short赋值失败

时间:2012-09-14 06:02:57

标签: c++ visual-studio

在尝试将提升为 int 时,我遇到了一些奇怪的行为,其中提升后的高2字节为0xFFFF。 AFAIK的高位字节应始终保持为0.请参阅以下代码:

    unsigned int test1 = proxy0->m_collisionFilterGroup;
    unsigned int test2 = proxy0->m_collisionFilterMask;
    unsigned int test3 = proxy1->m_collisionFilterGroup;
    unsigned int test4 = proxy1->m_collisionFilterMask;

    if( test1 & 0xFFFF0000 || test2 & 0xFFFF0000 || test3 & 0xFFFF0000 || test4 & 0xFFFF0000 )
    {
        std::cout << "test";
    }

一旦 cout 被击中,所涉及变量的值为:

Strange Promotion

请注意两个突出显示的值。我也看了一下反汇编,对我来说也很好看:

Disassembly

我的软件是针对使用VS 2008 SP1编译的x64。我还链接了Bullet Physics 2.80的开箱即用版本。代理对象是项目符号对象。

代理类定义如下(某些功能被修剪掉):

    ///The btBroadphaseProxy is the main class that can be used with the Bullet broadphases. 
///It stores collision shape type information, collision filter information and a client object, typically a btCollisionObject or btRigidBody.
ATTRIBUTE_ALIGNED16(struct) btBroadphaseProxy
{

BT_DECLARE_ALIGNED_ALLOCATOR();

    ///optional filtering to cull potential collisions
    enum CollisionFilterGroups
    {
            DefaultFilter = 1,
            StaticFilter = 2,
            KinematicFilter = 4,
            DebrisFilter = 8,
            SensorTrigger = 16,
            CharacterFilter = 32,
            AllFilter = -1 //all bits sets: DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter | SensorTrigger
    };

    //Usually the client btCollisionObject or Rigidbody class
    void*   m_clientObject;
    short int m_collisionFilterGroup;
    short int m_collisionFilterMask;
    void*   m_multiSapParentProxy;      
    int         m_uniqueId;//m_uniqueId is introduced for paircache. could get rid of this, by calculating the address offset etc.

    btVector3   m_aabbMin;
    btVector3   m_aabbMax;

    SIMD_FORCE_INLINE int getUid() const
    {
        return m_uniqueId;
    }

    //used for memory pools
    btBroadphaseProxy() :m_clientObject(0),m_multiSapParentProxy(0)
    {
    }

    btBroadphaseProxy(const btVector3& aabbMin,const btVector3& aabbMax,void* userPtr,short int collisionFilterGroup, short int collisionFilterMask,void* multiSapParentProxy=0)
        :m_clientObject(userPtr),
        m_collisionFilterGroup(collisionFilterGroup),
        m_collisionFilterMask(collisionFilterMask),
        m_aabbMin(aabbMin),
        m_aabbMax(aabbMax)
    {
        m_multiSapParentProxy = multiSapParentProxy;
    }
}
;

我之前从未遇到过这个问题,只是在升级到64位并集成bullet后才开始获取它。我遇到问题的唯一地方就是涉及子弹,所以我怀疑这个问题与某种方式有关,但我仍然非常困惑于什么可能使原始类型之间的分配不符合预期。

由于

2 个答案:

答案 0 :(得分:3)

您正在请求从已签名转换为无签名。这是非常严格的前进:

  • 您的来源值为-1。由于类型为short int,因此您的平台上的位为0xFFFF

  • 目标类型为unsigned int-1不能表示为unsigned int,但转换规则由标准定义:选择与-1模2一致的正值 N ,其中 N 是无符号类型的值位数。

    在您的平台上,unsigned int有32个值位,因此-1 modulo 2 32 的模块代表是0xFFFFFFFF

如果您自己的虚构规则应用于哪里,您可能希望得到结果0x0000FFFF,即65535,并且以任何明显或有用的方式与-1无关。

如果 想要进行转换,则必须手动对短类型执行模块化环绕:

short int mo = -1;
unsigned int weird = static_cast<unsigned short int>(mo);

Nutshell: C ++是关于,而不是表示

答案 1 :(得分:0)

  

AFAIK高位字节应始终保持为0

从短期推广到整体 算术转移(也称为签名班次)时, 回答你的问题就足以知道它是通过扩展最大字节值来增加的字节数来执行的;

示例:

short b;
int a = b; /* here promotion is performed, mechanism of it can be described by following bitwise operation: */
a = b >> (sizeof(a) - sizeof(b)); // arithmetic shift performed

重要的是要注意,在计算机表示有符号和无符号值的内存中可以是相同的,编译器生成的命令的唯一区别是:

示例:

unsigned short i = -1 // 0xffff
short j = 65535 // 0xffff

所以签名/无符号对于促销结果无关紧要,在两种情况下都会执行算术移位