为什么从 uint 中减去 int.MaxValue 与从 uint 中减去 int 类型变量不同?
Why is subtracting int.MaxValue from uint different from subtracting an int typed variable from uint?
至少从表面上看,这不是int溢出的问题,也不是uint溢出的问题。我知道这些值只重叠了一半,而且范围是相等的。事实上,我指望着那个。
背景: 有一个 returns uint 的 DotNet CRC 哈希算法,我需要将其转换为存储在 sql 中(缺少一个单位)。这种转换应该始终是可能的,因为两者的总范围是相等的,即使起点和终点不同。无需担心反转转换。我将其调试为 DotNet 4.0 和 4.6.1,结果相同。
我在这里莫名其妙:
在下面的代码示例中:
intForSqlStorageOK 成功。
但是 intForSqlStorageFail1 抛出运行时异常。
他们有什么不同?
{
uint uIntToBeStoredInSql = 591071; //CRC32 hash result
int intMaxValue = int.MaxValue;
int intForSqlStorageOK = Convert.ToInt32(uIntToBeStoredInSql - intMaxValue - 1);
//System.OverflowException: 'Value was either too large or too small for an Int32.'
int intForSqlStorageFail1 = Convert.ToInt32(uIntToBeStoredInSql - int.MaxValue - 1);
int intForSqlStorageFail2 = Convert.ToInt32(uIntToBeStoredInSql - Convert.ToUInt32(int.MaxValue) - 1);
int intForSqlStorageFail3 = checked(Convert.ToInt32(uIntToBeStoredInSql - int.MaxValue - 1));
int intForSqlStorageFail4 = unchecked(Convert.ToInt32(uIntToBeStoredInSql - int.MaxValue - 1));
int intForSqlStorageFail5; //??? probably many others ???
///this SO led to this workaround, which is just clobbering the problem by adding memory. doesn't explain the difference above.
///
int intForSqlStorageOK2 = Convert.ToInt32(Convert.ToInt64(uIntToBeStoredInSql) - int.MaxValue - 1);
///Thanks ckuri in comments - this is way more terse and somehow still arrives at same result
int intForSqlStorageOK3 = (int)uIntToBeStoredInSql - intMaxValue - 1;
int intForSqlStorageOK4 = (int)uIntToBeStoredInSql - int.MaxValue - 1;
}
感谢大家的评论!学到很多
根据specification,int.MaxValue
可以隐式转换为uint
类型,而非常量int
表达式不可以,因为在编译时编译器不会知道 int
表达式的值是否在 uint
类型的范围内。
如果您应用运算符解析规则,那么您会看到,uIntToBeStoredInSql - intMaxValue - 1
被解释为 (long)uIntToBeStoredInSql - (long)intMaxValue - 1L
,总值 -2146892577L
(在 [=12= 的范围内) ]类型)。
虽然 uIntToBeStoredInSql - int.MaxValue - 1
在 unchecked
上下文中被解释为 uIntToBeStoredInSql - (uint)int.MaxValue - 1u
,总值 2148074719u
(不在 int
类型的范围内)并且 OverflowException
checked
上下文中的异常。
至少从表面上看,这不是int溢出的问题,也不是uint溢出的问题。我知道这些值只重叠了一半,而且范围是相等的。事实上,我指望着那个。
背景: 有一个 returns uint 的 DotNet CRC 哈希算法,我需要将其转换为存储在 sql 中(缺少一个单位)。这种转换应该始终是可能的,因为两者的总范围是相等的,即使起点和终点不同。无需担心反转转换。我将其调试为 DotNet 4.0 和 4.6.1,结果相同。
我在这里莫名其妙:
在下面的代码示例中:
intForSqlStorageOK 成功。
但是 intForSqlStorageFail1 抛出运行时异常。
他们有什么不同?
{
uint uIntToBeStoredInSql = 591071; //CRC32 hash result
int intMaxValue = int.MaxValue;
int intForSqlStorageOK = Convert.ToInt32(uIntToBeStoredInSql - intMaxValue - 1);
//System.OverflowException: 'Value was either too large or too small for an Int32.'
int intForSqlStorageFail1 = Convert.ToInt32(uIntToBeStoredInSql - int.MaxValue - 1);
int intForSqlStorageFail2 = Convert.ToInt32(uIntToBeStoredInSql - Convert.ToUInt32(int.MaxValue) - 1);
int intForSqlStorageFail3 = checked(Convert.ToInt32(uIntToBeStoredInSql - int.MaxValue - 1));
int intForSqlStorageFail4 = unchecked(Convert.ToInt32(uIntToBeStoredInSql - int.MaxValue - 1));
int intForSqlStorageFail5; //??? probably many others ???
///this SO led to this workaround, which is just clobbering the problem by adding memory. doesn't explain the difference above.
///
int intForSqlStorageOK2 = Convert.ToInt32(Convert.ToInt64(uIntToBeStoredInSql) - int.MaxValue - 1);
///Thanks ckuri in comments - this is way more terse and somehow still arrives at same result
int intForSqlStorageOK3 = (int)uIntToBeStoredInSql - intMaxValue - 1;
int intForSqlStorageOK4 = (int)uIntToBeStoredInSql - int.MaxValue - 1;
}
感谢大家的评论!学到很多
根据specification,int.MaxValue
可以隐式转换为uint
类型,而非常量int
表达式不可以,因为在编译时编译器不会知道 int
表达式的值是否在 uint
类型的范围内。
如果您应用运算符解析规则,那么您会看到,uIntToBeStoredInSql - intMaxValue - 1
被解释为 (long)uIntToBeStoredInSql - (long)intMaxValue - 1L
,总值 -2146892577L
(在 [=12= 的范围内) ]类型)。
虽然 uIntToBeStoredInSql - int.MaxValue - 1
在 unchecked
上下文中被解释为 uIntToBeStoredInSql - (uint)int.MaxValue - 1u
,总值 2148074719u
(不在 int
类型的范围内)并且 OverflowException
checked
上下文中的异常。