整数的转换、扩展、截断和运算
整数的转换
上一章介绍了有符号整数和无符号整合的表示方式。那么在C语言中,一个整数常量的大小和符号是什么呢?请看如下定义
#define A 123
#define B 128
A和B是两个宏,经过预处理,A和B会被替换为两个整数。那么编译器是如何存储这两个整数的呢?也就是说A和B有没有符号?在栈/静态存储区中占几个字节呢?
默认的,常量被定义为有符号的,而大小则由所能容纳此整数的最小类型来定义(《C和指针》3.1基本数据类型)。以上两个定义,A和B都是有符号的,char的表示范围为0-127,short的范围为0-32767,所以,A被当作一个有符号的char存放,B超过了有符号char所能表示的最大值,所以被当作为有符号short存放。但实际情况是否如此呢?
#define A 123
#define B 140
printf("A size = %d\r\n", sizeof(A) );
printf("B size = %d\r\n", sizeof(B) );
A size = 4
B size = 4
我的环境是UBUNTU 2.6.35内核,X86,gcc4.4.5,可见在此环境中,无论整数常量被定义为多大,存储都是四个字节。具体要根据实际的反汇编代码来判断,这个等下一章时会进行验证。
如果想规定常量的符号和大小,需要在后面加上U(u)和L(l)来限定。123U,则表示为无符号的char;123UL,则会表示为无符号的long(如果默认储存为int,那么L就没有用了?)
如果一种类型的变量被赋给另外一种类型的变量时,会发生隐式转换
int x = -1;
unsigned int u = 2147483648;
show_bits( (unsigned char *)&x, sizeof(x), "x bits:" );
show_bits( (unsigned char *)&u, sizeof(u), "u bits:" );
printf("x = %u, %d\r\n", x, x );
printf("u = %u, %d\r\n", u, u );
结果:
x bits:
11111111 11111111 11111111 11111111
u bits:
00000000 00000000 00000000 10000000
由于机器是小端的,所以上面U的正常比特位应该是
10000000 00000000 00000000 00000000
x = 4294967295, -1
u = 2147483648, -2147483648
可以看出,同样一个整数,当作正数和当作负数的结果,是不一样的。
如果一个表达式中运算数的符号不同,那么编译器会把有符号变量强制转换为无符号类型,所以,当使用“<和>”判断时,要格外注意。最好的方法,是用X - Y与0相比,看下面几个使用<和>的例子:
#define A -1
#define B 0
if( A < B )
{
printf("expression is True\r\n");
}
else
{
printf("expression is False\r\n");
}
结果:expression is True。编译器认为A和B都是有符号的,-1 < 0
#define A -1
#define B 0U
if( A < B )
{
printf("expression is True\r\n");
}
else
{
printf("expression is False\r\n");
}
结果:expression is False。编译器将A都转换为无符号数,0xFFFFFFFF显然比0大
#define A 2147483647
#define B (int)2147483648U
printf("A = %.8x, B = %.8x\r\n", A, B );
if( A > B )
{
printf("expression is True\r\n");
}
else
{
printf("expression is False\r\n");
}
结果:
A = 7fffffff, B = 80000000
expression is True。用(int)将B转换为有符号数,此时B被看作为负数
整数的扩展与截取
较小类型的数据扩展为较大类型时,如果是无符号整数,则前头填充0,称为零扩展(zero extension);如果是有符号的,前头按符号为填充,称为符号扩展(sign extension)
short sx = -12345;
unsigned usx = 53191;
int x = sx;
unsigned ux = usx;
printf("x = %.8x\r\n", x );
printf("ux = %.8x\r\n", ux );
结果:
x = ffffcfc7
ux = 0000cfc7