int main()
{
char a = -1;
signed char b = -1;
unsigned char c = -1;
printf("a=%d,b=%d,c=%d", a, b, c);
return 0;
}
//运行结果:a=-1,b=-1,c=255
首先,我们要了解到:在C语言中,char类型变量在内存中存储占1个字节=8个比特位;int类型占4个字节=32个比特位。而数值是以二进制补码的形式在内存中存储(其中,正数:原码=反码=补码;负数: 反码=原码除符号位按位取反、补码=反码+1)。数值有正数和负数之分,存储类型也有有符号(signed 【一般省略】)和无符号(unsigned)之分。
以char类型变量为例探索数值在内存中的存储:
(1)signed char类型的范围是-128~127;(最高位是符号位:0表示正数、1表示负数)
原码 | 反码 | 补码 | 十进制 | 注释 |
0000 0000 | 0000 0000 | 0000 0000 | 0 | 最小的正数 |
0111 1111 | 0111 1111 | 0111 1111 | 127 | 最大的正数 |
1000 0001 | 1111 1110 | 1111 1111 | -1 | 最大的负数 |
1111 1111 | 1000 0000 | 1000 0001 | -127 | |
1000 00000 | 1111 1111 | 1000 0000 | -128 | 最小的负数 |
(2)unsigned char类型的范围是0~255;(无符号位,每一位都表示数值)
原码 | 反码 | 补码 | 十进制 | 注释 |
0000 0000 | 0000 0000 | 0000 0000 | 0 | 最小的正数 |
1111 1111 | 1111 1111 | 1111 1111 | 255 | 最大的正数 |
char a = -1;
signed char b=-1;
//两者相等(signed可省略)
unsigned char c = -1;
printf("a=%d,b=%d,c=%d", a, b, c);
运算及打印过程:
-1 | signed char | unsigned char |
原码(int) | 1000 0000 0000 0000 0000 0000 0000 0001 | 1000 0000 0000 0000 0000 0000 0000 0001 |
反码(int) | 1111 1111 1111 1111 1111 1111 1111 1110 | 1111 1111 1111 1111 1111 1111 1111 1110 |
补码(int) | 1111 1111 1111 1111 1111 1111 1111 1111 | 1111 1111 1111 1111 1111 1111 1111 1111 |
截断存入 char类型变量 | 取后8个比特位: 1111 1111 | 取后8个比特位: 1111 1111 |
%d打印 整型提升 | 按符号位全补1: 1111 1111 1111 1111 1111 1111 1111 1111 | 无符号直接补0: 0000 0000 0000 0000 0000 0000 1111 1111 |
转成原码输出 | 1000 0000 0000 0000 0000 0000 0000 0001 【-1】 | 0000 0000 0000 0000 0000 0000 1111 1111 【255】 |
char a = -128;
printf("%u\n", a);
//4294967168
char a = 128;
printf("%u\n", a);
//4294967168
char | -128 | 128 |
原码(int) | 1000 0000 0000 0000 0000 0000 1000 0000 | 0000 0000 0000 0000 0000 0000 1000 0000 |
反码(int) | 1111 1111 1111 1111 1111 1111 0111 1111 | 0000 0000 0000 0000 0000 0000 1000 0000 |
补码(int) | 1111 1111 1111 1111 1111 1111 1000 0000 | 0000 0000 0000 0000 0000 0000 1000 0000 |
截断存入 char类型变量 | 取后8个比特位: 1000 0000 | 取后8个比特位: 1000 0000 |
%d打印 整型提升 | 按符号位全补1: 1111 1111 1111 1111 1111 1111 1000 0000 | 按符号补1: 1111 1111 1111 1111 1111 1111 1000 0000 |
转成原码输出 | 1111 1111 1111 1111 1111 1111 1000 0000【%u无符号】 | 1111 1111 1111 1111 1111 1111 1000 0000【%u无符号】 |
unsigned int 类型例(经典):
#include<Windows.h>
int main()
{
unsigned int i;
//0000...0000 0000
//1111...1111 1111
//-1、-2、-3...的补码正常存到内存中
//但按照无符号打印,直接将其当作原码打印
//i是无符号数,在进行运算时,也将补码直接当作原码运算
for (i = 9; i >= 0; i--)
//控制循环 一直将补码视为无符号的原码,一直循环
{
printf("%u\n", i);
//将补码视为无符号的原码一直打印
printf("%d\n", i);
//将补码转换成原码打印
Sleep(1000);
}
return 0;
}
int main()
{
char a[1000];
int i;
for (i = 0; i < 1000; i++)
{
a[i] = -1 - i;
//-1 -2 -3 -4...-128 127 126...3 2 1 0 -1 -2...
}
printf("%d", strlen(a));
//strlen是求字符串长度,计算字符串中
// ‘\0’(ASCII为0)之前出现多少字符
return 0;
}
char类型变量循环做减法或循环做加法时,会循环-127~128,因为数值是int类型,64比特位;char类型始终截断其后8位。此代码会一直循环下去,但strlen取长度到0为止。