从int到longlong的危险转换:没有警告?

时间:2017-06-22 08:02:58

标签: c++ visual-c++

UINT One = 1;
LONG     mylong      = LONG(-1) * One;
LONGLONG mylonglong1 = LONG(-1) * One;
LONGLONG mylonglong2 = LONG(LONG(-1) * One);

mylongmylonglong1mylonglong2中存储的值是多少?

mylong      = 0xffffffff         (ok)
mylonglong1 = 0x00000000ffffffff (why?)
mylonglong2 = 0xffffffffffffffff (ok)

我很惊讶地知道mylonglong1的结果,更惊讶的是没有编译警告。

为什么将LONG分配给LONGLONG会导致左边的填充为零?

项目中发生的事情是使用函数CFile :: Seek()

时遇到的问题
virtual LONG Seek( LONG lOff, UINT nFrom );

此处定义:https://msdn.microsoft.com/en-us/library/aa270542(v=vs.60).aspx 迁移到

virtual ULONGLONG Seek( LONGLONG lOff, UINT nFrom);

此处定义https://msdn.microsoft.com/library/b2eb5757-d499-4e67-b044-dd7d1abaa0f8.aspx#cfile__seek

迁移后,它不再起作用,因为lOff的参数转换没有给出预期的结果。

1 个答案:

答案 0 :(得分:2)

在表达式(-1) * (UINT)1中,第一个操作数根据operand conversion rules转换为UINT

  

否则,如果无符号操作数的转换等级大于或等于带符号操作数的转换等级,则带符号操作数将转换为无符号操作数的类型。

因此,我们有一个无符号乘法,结果类型为UINT。从UINTLONGLONG的转换非常简单,因为LONGLONG可以代表UINT所代表的每个数字,在本例中为0xffffffff。这就是你最终得到0x00000000ffffffff的方式。

现在,当您执行LONG(LONG(-1) * (UINT)1)时,上述规则仍适用,但您最终会将未签名的0xffffffff转换为-1,然后将其符号扩展为LONGLONG

P.S:我假设Win32 / Win64,其中UINT和LONG是32位,LONGLONG是64位。