无符号类型的误导

     近日在写程序时,无意间遇到了错误,经反复推敲和调试,确定了错误就出在无符号类型下,百度许久,总结一下。

      相信很多人都知道关于C语言的标准大致有两种,一个是老的K&R C标准,一个是新的ANSI C标准(当然,这也不能算新了),这两种标准关于一些细节方面有很多的不同,但毕竟标准只允许改正,不允许废除,就像intel 8086的段地址:偏移地址的寻址方式也不得不为了兼容性而一直保留着一样,而C语言标准的改变,有人称之为“安静的改变”。

      这段代码可以告诉你,你现在使用的到底是K&R C还是ANSI C,因为虽然-1的位模式是一样的,但是在这两种不同的编译器下的解释确不尽相同,ANSI C将其解释为负数,而K&R C奇怪的将其解释为正数。

      说奇怪也不算奇怪,因为都是有标准可以参照和拿来解释的:

K&R C采用无符号保留(unsigned preserving)原则,就是当一个无符号类型与int或更小的整形混合使用时,结果类型是无符号类型。这是个简单的规则,与硬件无关。但是,它却会如上面的例子那样,使一个负数丢失符号位。

ANSI C采用值保留(value preserving)原则,就是当几个整形操作数像上面例子这样混合使用时,结果类型有可能是有符号数,也可能是无符号数,取决于操作数的类型的相对大小。

      我遇到的问题是这样的,参见下面的例子:

      经过调试发现,原本if判断语句应该成立的地方却不是这样的,然后翻阅sizeof()的介绍时发现其返回值类型为size_t,即unsigned int,而if语句在signed int和unsigned int之间进行大小判断时,d被升级为unsigned int类型,这就导致了-1被强制转换成了一个非常大的数,致使表达式为假。

     其实要修正这个问题也很简单,进行强制类型转换,即:

     经过这一次,需要更正一个观点,不要因为某些数不可能出现负数(如年龄)而想当然的将其定义为无符号数,这样可能会在后面的编程中,莫名其妙的出现上次问题。建议只在使用位段和二进制掩码时,才去使用无符号数。应该在表达式中使用强制类型转换,使操作数均为有符号数或者无符号数,不要由编译器去选择结果的类型。

原文地址:https://www.cnblogs.com/pang123hui/p/2309958.html