有符号/无符号比较给出了意想不到的结果[重复]
Posted
技术标签:
【中文标题】有符号/无符号比较给出了意想不到的结果[重复]【英文标题】:Signed/unsigned comparison gives unexpected result [duplicate] 【发布时间】:2014-05-02 15:54:38 【问题描述】:a 是有符号整数,包含 -100 b 是一个无符号整数,包含 500
a<b returns FALSE!!
到底为什么? :P
我可以将 b 转换为 signed int 并获得正确的结果, 但原样离开,结果让我大吃一惊, 因为我不知道为什么 -100
如果我们保持原样,即第一个签名的和 第二个未签名,那么为什么要
这真的很令人困惑。
现在我必须更正我的所有代码,寻找 有符号和无符号整数之间的比较,以及强制转换 这两个变量都是我的意思。 :-/
还有其他需要注意的情况吗 混合有符号和无符号类型时?
请不要回复明显的“一般使用 无符号类型是不建议的,你为什么不坚持 只有签名类型?你会更安全”。谢谢。
干杯。
【问题讨论】:
你也显示所有相关代码怎么样? 更好的是:将有符号转换为无符号并具有a<b
,a=500 和b=-100,或者将无符号转换为有符号并具有a<b
,a=3000000000 和b=-1? IMO,两者都不好,这就是为什么你不应该比较不同符号的值。当您执行此操作时,Clang 和 gcc 会警告您,不确定 Visual Studio。
使用正确的警告级别,您应该会收到针对此类代码的警告。类似于implicit conversion changes signedness: 'int' to 'unsigned long'
。
Now I have to correct all of my code, looking for comparisons between signed and unsigned ints, and cast both variables to the type I mean.
编译器没有生成警告,说明您在表达式中混合了有符号和无符号整数吗?
“就像编译器自动将 a 强制转换为无符号类型”。是的。谷歌“C 常用算术转换”。
【参考方案1】:
根据整数提升的规则,当你对相同位数的有符号数和无符号数进行运算时,有符号数会转换为无符号数。
看看这两个数字的二进制表示。当a
被重新解释为无符号时,就变成了429496719610:
a=-10010 变为 11111111111111111111111110011100
b=+50010 变为 00000000000000000000000111110100
如您所见,当两个数字都被解释为无符号时,a
大于 b
。
在混合有符号和无符号类型时,我还需要注意什么其他情况?
这个问题的答案是响亮的“是”——当你混合有符号和无符号类型时,你应该非常小心。这就是当有符号和无符号类型混合在同一个表达式中时 C++ 编译器发出警告的原因。解决所有这些警告很重要,主要是因为它可以帮助您了解自己的程序。
你为什么不坚持只使用签名类型?
这不是一个好的建议 - 在某些情况下您需要 unsigned 类型,因为您的程序模型不能为负数,或者因为您使用整数类型来实现它的能力存储位模式——例如,表示一个小集合的一个子集。无符号类型本身对您的程序来说并不坏,只要您避免将它们与负数混合,或者在需要发生这种混合时提供显式类型转换。
【讨论】:
【参考方案2】:在混合有符号和无符号类型时,我还需要注意什么其他情况?
是的,有很多情况。任何涉及混合数据类型的二元运算符表达式都必须通过转换为某些常见类型来解决。如果没有提供显式转换,编译器将根据语言规则提供隐式转换。
对于复杂的表达式,可能会发生许多转换,而且通常很难确定会发生什么。您不应该依赖您对有些晦涩难懂的规则的了解 - 清晰比聪明更容易,尤其是如果代码稍后可能由其他人维护。
理想情况下,你应该努力在表达式中实现类型一致性,如果这是不可能的,你应该确保你的编译器警告级别设置得足够高,以警告不安全的隐式转换,并将所有警告视为错误并由 修复它们适当的演员表。如果您的编译器未生成此类警告,您可能会使用不同的编译器 - 不一定用于部署,而是作为辅助检查。如果没有静态分析工具可能会有所帮助。
一般而言,您可以通过对所有整数算术数据类型(即您将对其执行算术运算的数字)优先使用纯 int
来避免大多数问题。即使值不应该是负数,只要int
的正数范围足够,最好使用它来避免算术运算中的隐式转换。
【讨论】:
以上是关于有符号/无符号比较给出了意想不到的结果[重复]的主要内容,如果未能解决你的问题,请参考以下文章