【C语言】char类型如何在内存中存储?
慕雪年华

@[toc]

引子

上篇博客向大家介绍了int类型在内存中的存储方式【链接】

本篇博客我们继续往后,看看整形家族里的char类型是如何在内存中存储的吧!


char类型

字符类型包括以下两种形式

  • unsigned char 无符号

  • signed char 有符号

用一个简单的printf来看看它们在打印上的区别

1
2
3
4
5
6
7
8
9
10
#include<stdio.h>
int main()
{
char a=-1;
signed char b=-1;
unsigned char c=-1;
printf("a=%d b=%d c=%d\n",a,b,c);

return 0;
}

打印结果为

1
a=-1 b=-1 c=255

这里我们可以得出两个结论

1.在VS编译器下,char默认为signed char

2.unsigned char的处理方式和signed不同

无符号数的处理可以看我之前写的这一篇博客👉【链接】


存放和提升

例一:-1

先写出-1的原反补码

1
2
3
10000000 00000000 00000000 00000001  -1原码
11111111 11111111 11111111 11111110 反码
11111111 11111111 11111111 11111111 补码

在内存中存放的时候,a、b、c存放的都是补码的最后一个字节,即11111111

而当我们用%d打印的时候,会发生整型提升

整型提升的概念我写过另外一篇博客👉【点我】

这里就是有符号和无符号处理不同的地方了

因为a、b都是有符号的char,所以编译器会将最高位视为符号位进行提升

所以a、b进行整型提升后的结果如下

1
11111111 11111111 11111111 11111111//提升后a、b的补码

而c是无符号char类型,编译器会在最高位补0

1
00000000 00000000 00000000 11111111//提升后c的补码

此时最高位为0,编译器将其视为正数,此时补码就是原码,打印255

符号位 0为正,1为负

正数的原码、反码、补码相同

例二:-128

1
2
3
4
5
6
7
#include <stdio.h>
int main()
{
char a=-128;
printf("%u\n",a);
return 0;
}

打印的结果并不是-128

1
4294967168

-128的原反补码

1
2
3
10000000 00000000 00000000 10000000  -128原码
11111111 11111111 11111111 01111111 反码
11111111 11111111 11111111 10000000 补码

a中存放的是1000 0000

最高位视为符号位,整型提升后

1
11111111 11111111 11111111 10000000//新的补码

但因为这里是**%u打印,视作无符号数**

此时原反补码一致,直接视作原码进行计算

打印结果即为4294967168

image

如果我们让a等于128,结果相同

image

char变量中存放数值的范围

先来看看这样一串代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <string.h>
int main()
{
char a[1000];
int i;
for (i = 0; i < 1000; i++)
{
a[i] = -1 - i;
}
printf("%d", strlen(a));

return 0;
}

代码的结果如下:255

image

在初始化的时候,我们设定了a[1000],a数组里面理应有1000个元素

那strlen函数求得的结果为何是255,而不是1000呢?


实际char类型中的数据范围分为有符号和无符号两种

  • signed char 1byte-8bit,取值范围-128~127
  • unsigned char 1byte-8bit,取值范围0~255

以二进制表示,如下图所示

image

因为无符号char类型中,八位补码视作原码进行计算

而有符号char类型中,在计算的时会将首位视为符号位

1
2
3
11111111 //补码
11111110 //反码,补码减1
10000001 //源码,读出-1
1
2
3
10000001//补码
10000000//反码
11111111//首位符号位不读,其他位读出-127
1
2
3
4
10000000//补码
这个二进制位不能-1,直接视作源码计算
不能忘记这是个负数!
10000000//源码读出128,加上负号为-128

下面这幅图可以形象地表示出char类型数据范围

image

1
2
3
4
5
6
7
char a[1000];
int i;
for (i = 0; i < 1000; i++)
{
a[i] = -1 - i;
}
printf("%d", strlen(a));

上面那串代码里面的for循环,实则是一直给数组a中从-1开始赋值到-128,再从127赋值到1,0……如此循环赋值,直到i=1000跳出循环。

而我们的strlen函数在计算数组长度的时候,遇到第一个0就会停止计算

这样我们就得出了答案为255!

如何查询范围定义?

我们可以通过头文件<limits.h>来查找范围定义

在VS2019里面右键该头文件,点击“转到文档”

image

这里我们就能看到各种数据类型的数据范围

image

我们还可以看看其他的数据类型

有符号short为例,它的范围是-32678到32767

image

image


结语

以一串代码示例结束本篇博客吧!

image

感谢你看到最后!

点个赞呗,这对我灰常重要!!😘