1. 有符号数和无符号数:
C支持所有整形数据类型的有符号数和无符号数运算。尽管C标准并没有指定某种有符号数的表示,但是几乎所有的机器都使用二进制补码。通常,大多数数字默认都使有符号的,C也允许无符号数和有符号数之间的转换,转换原则是基本的位表示保持不变。因此在一台二进制补码机器上,当从无符号数转换为有符号数时,效果就是应用U2Tw,而从有符号转换为无符号数时,就是应用函数T2Uw,其中w表示数据类型的位数。
T2Uw(x) = (x<0)?(x+2w) :x;
U2Rw(x) = (x<2w-1)?x:(x-2w);
当执行一个运算时,如果它的一个运算数是有符号的而另一个是无符号的,那么C会隐含地将有符号参数强制转换为无符号数,并假设这两个数都是非负的,来执行这个运算。e.g.(show_*函数参考《应考虑字节顺序(大小端问题)的几种情况》 ):
{
printf(-2147483647-1==2147483648U?"1 ":"0 ");
show_unsignedInt(2147483648U);
show_int(-2147483647-1);
}
2. 扩展数字的位表示:
当将一个较小的数据类型转换到一个较大的数据类型时,需要扩展一个数字的位表示。要将一个无符号数转换为一个更大的数据类型,我们只要简单地在表示的开头添加0,这种扩展称为零扩展(Zero Extension);要将一个二进制补码数字转换为一个更大的数据类型,扩展时需要填充最高有效位的值,这种扩展称为符号扩展(Zero Extension)。e.g.:
{
short sx = -12345;
unsigned short usx = sx;
int x = sx;
unsigned ux = usx;
printf("sx=%d ",sx);
show_short(sx);
printf("usx=%d ",usx);
show_unsignedShort(usx);
printf("x=%d ",x);
show_int(x);
printf("ux=%d ",ux);
show_unsignedInt(ux);
}
运行结果和结果分析:
sx=-12345 cfc7
usx=53191 cfc7
x=-12345 ffffcfc7(符号扩展,算术右移)
ux=53191 0000cfc7(零扩展,逻辑右移)
另外:从一个数据大小到另一个数据大小,以及无符号和有符号数字之间的转换的相对顺序能够影响一个程序的行为。e.g.(short sx=-12345): (unsigned)(int)sx != (unsigned)(unsigned short)sx
3. 截断数字的位表示:
当将一个较小的数据类型转换到一个较大的数据类型时,需要截断该数字的高N位。