天天看点

C语言signed和unsigned的使用与注意事项

作者:霸都嵌入式

C语言中,signed和unsigned是两个类型修饰符,它们可以用来修饰整数类型,表示变量的符号属性。signed表示变量是有符号的,可以存储正数和负数;unsigned表示变量是无符号的,只能存储非负数。在使用signed和unsigned时,需要注意以下几个方面:

signed和unsigned的使用方法

- signed和unsigned可以修饰int、short、long和long long等整数类型。例如:

signed int a; //有符号整型
unsigned int b; //无符号整型
signed short c; //有符号短整型
unsigned short d; //无符号短整型
signed long e; //有符号长整型
unsigned long f; //无符号长整型
signed long long g; //有符号long long类型
unsigned long long h; //无符号long long类型           

- signed是默认的,如果不加任何修饰符,变量就是有符号的。因此,int等价于signed int,short等价于signed short,long等价于signed long,long long等价于signed long long。例如:

int i; //等价于signed int i;
short j; //等价于signed short j;
long k; //等价于signed long k;
long long l; //等价于signed long long l;           

- unsigned则需要显式给出,表示变量没有符号位。例如:

unsigned int m; //无符号整型
unsigned short n; //无符号短整型
unsigned long o; //无符号长整型
unsigned long long p; //无符号long long类型           

- 对于long和long long常量,可以使用后缀直接给出unsigned的属性。例如:

120L; //L后缀表示long常量
120LU; //LU后缀表示unsigned long常量
120LLU; //LLU后缀表示unsigned long long常量
120ull; //ull后缀也表示unsigned long long常量           

signed和unsigned的区别

- signed和unsigned的区别主要在于是否把存储的某一位看做符号位。对于n位的二进制数,如果是有符号的,最高位是符号位,0表示正数,1表示负数;如果是无符号的,没有符号位,所有位都表示数值。

- 有符号数在计算机中用补码表示。正数的补码是其本身;负数的补码是其绝对值取反加一。例如:

8位有符号数5的补码为:00000101
8位有符号数-7的补码为:11111001(|-7|=7 -> 00000111 -> 11111000 -> +1)           

- 无符号数在计算机中用原码表示。原码就是二进制数本身。例如:

8位无符号数5的原码为:00000101
8位无符号数7的原码为:00000111           

- 因此,同样一个二进制数,在不同的类型下可能表示不同的值。例如:

8位二进制数11111001,在有符号类型下表示-7,在无符号类型下表示249。           

- 同样长度的有符号数和无符号数能够存储的数值范围也不同。对于n位的二进制数,如果是有符号的,最小值为-2^(n-1),最大值为2^(n-1)-1;如果是无符号的,最小值如果是无符号的,最小值为0,最大值为2^n-1。例如:

8位有符号数的范围是-128 ~ 127
8位无符号数的范围是0 ~ 255           

signed和unsigned的注意事项

- 在使用signed和unsigned时,需要注意以下几个方面:

- 在进行算术运算时,如果有符号数和无符号数混合运算,会发生隐式类型转换,导致结果不正确或者溢出。例如:

int a = -1;
unsigned int b = 1;
printf("%d\n", a + b); //输出0,因为a被转换为无符号数,其值为4294967295(2^32-1)
printf("%u\n", a + b); //输出4294967296,因为结果溢出了无符号数的范围           

- 在进行比较运算时,如果有符号数和无符号数混合比较,也会发生隐式类型转换,导致结果不正确。例如:

int a = -1;
unsigned int b = 1;
printf("%d\n", a < b); //输出0,因为a被转换为无符号数,其值为4294967295(2^32-1),大于b
printf("%d\n", a > b); //输出1,同理           

- 在进行位运算时,如果有符号数和无符号数混合运算,也会发生隐式类型转换,导致结果不正确。例如:

int a = -1;
unsigned int b = 1;
printf("%d\n", a & b); //输出1,因为a被转换为无符号数,其值为4294967295(2^32-1),与b按位与后仍然是1
printf("%d\n", a | b); //输出-1,因为结果被转换为有符号数,其值为4294967295(2^32-1),按照补码规则表示-1           

- 在进行赋值运算时,如果有符号数和无符号数混合赋值,也会发生隐式类型转换,导致结果不正确。例如:

int a = -1;
unsigned int b = 1;
a = b; //a的值变为1
b = a; //b的值变为4294967295(2^32-1)           

- 为了避免这些问题,在使用signed和unsigned时,应该尽量保持类型一致,或者使用强制类型转换来明确表达意图。例如:

int a = -1;
unsigned int b = 1;
printf("%d\n", (int)(a + b)); //输出0,强制将结果转换为有符号数
printf("%u\n", (unsigned int)(a + b)); //输出4294967296,强制将结果转换为无符号数
printf("%d\n", (int)a < (int)b); //输出1,强制将两个操作数都转换为有符号数
printf("%d\n", (unsigned int)a > (unsigned int)b); //输出0,强制将两个操作数都转换为无符号数           

系列文章持续更新,如果觉得有帮助请点赞+关注!

继续阅读