目录
- char
- unsigned char
- signed char
- short
- unsigned short[int]
- signed short[int]
- int
- unsigned int
- signed int
- long
- unsigned long[int]
- signed long[int]
⚠️
注意:unsigned char 是无符号的char;signed char 是有符号的char
若以后创建的变量只会存正数,就可以使用 unsigned ,对于用 short 、int 还是 long long 要考虑数值的大小
- float
- double
数组
struct 结构体类型
enum 枚举
union 联合体
- int* pi;
- char* pc;
- float* pf;
- void* pv;
void 表示空类型(无类型)
通常应用于函数的返回类型、函数的参数、指针类型。
数据在内存中是以 二进制 的形式存储
对于整数来说:
整数二进制有3中表示形式:原码、反码、补码
正整数:原码、反码、补码相同
负整数:原码、反码、补码是要进行计算的
计算方法:
按照数据的数值直接写出的就是原码
原码的符号位不变,其它位按位取反,得到的就是反码
反码 +1 得到的就是补码
⚠️
注意:整数在内存中存储的是补码。
例子:
- #include<stdio.h>
-
- int main()
- {
- int a = -10;
- //10000000000000000000000000001010 - 原码
- //11111111111111111111111111110101 - 反码
- //11111111111111111111111111110110 - 补码
- return 0;
- }
内存中是以十六进制展示的,而我们写出的是二进制,如果把二进制转化成十六进制,再进行比较就可以看出内存中存的是原码、反码、还是补码。
二进制的四个位可以换一个十六进制位,前面28个比特位可以换7个F,0110可以换成6,也就是FFFFFFF6,根据前面的图片可以发现在内存中是倒着存的,这也说明了整数在内存中存的是补码。那么为什么会倒着存?以及为什么存的是补码?将在后面进行解释。。
为什么在内存中存的是补码,而不是原码或反码呢?
原因:在计算机系统中,数值一履用补码表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码和原码相互相互转换,其运算过程是相同的,不需要额外的硬件电路。
例子:
- #include<stdio.h>
-
- int main()
- {
- //1 - 1;
- //由于CPU只有加法器,所以使用加负1来代替减1
- //1 + (-1);
- //假设使用原码来计算:
- //1的原码: 00000000000000000000000000000001
- //-1的原码:10000000000000000000000000000001
- //1 + (-1)的结果是:1000000000000000000000000000010
- //转化为十进制是-2,发现并不是我们想要的值
- return 0;
- }
结论:使用原码计算,无法得到我们预期想得到的值。
若使用补码计算:
- #include<stdio.h>
-
- int main()
- {
- //1 - 1;
- //由于CPU只有加法器,所以使用加负1来代替减1
- //1 + (-1);
- //假设使用原码来计算:
- //1的补码: 00000000000000000000000000000001
-
- //-1的原码:10000000000000000000000000000001
- //-1的反码:11111111111111111111111111111110
- //-1的补码:11111111111111111111111111111111
-
- //1的补码: 00000000000000000000000000000001
- //-1的补码:11111111111111111111111111111111
- //1 + (-1)的结果是:00000000000000000000000000000000
- //转化为十进制是0,是我们想要的值
- return 0;
- }
结论:使用补码计算,可以得到我们预期想得到的值,所以要使用补码计算。
为什么整数里的正数和负数在内存中是倒着存储的?
解决这个问题要先介绍大端和小端的。那么什么是大端小端?
什么是大端小端:
大端(存储)模式:是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中。
小端(存储)模式:是指数据的高位保存在内存的低地址中,而数据的低位,保存在内存的高地址中。
为什么会有大端和小端:
这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或是32位的处理器,由于寄存器的宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端模式和小端存储模式。
例子:

这里展示用的是16进制,但内存中存的是二进制
正着存倒着存都可以,但是要怎么存进去的,怎么拿出来。
后面两种的存储顺序太复杂了,可以这样存,但是使用起来太复杂了。所以也就保留了前面两种较为简单的顺序。
这四个字节是按照什么样的顺序存在内存中的,我们讨论的是存储在内存中字节的顺序,所以就叫字节序。
字节序分两种:大端字节序,小端字节序。
请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序
- #include<stdio.h>
-
- int main()
- {
- int a = 1;
- char* p = (char*)&a;
- if (*p == 1)
- {
- printf("小端\n");
- }
- else
- {
- printf("大端\n");
- }
- return 0;
- }
函数写法:
- #include<stdio.h>
-
- int check()
- {
- int a = 1;
- char* p = (char*)&a;
- if (*p == 1)
- {
- return 1;
- }
- else
- {
- return 0;
- }
- }
-
- int main()
- {
- int ret = check();
- if (1 == ret)
- {
- printf("小端\n");
- }
- else
- {
- printf("大端\n");
- }
- return 0;
- }
函数写法的优化版本:
- #include<stdio.h>
-
- int check()
- {
- int a = 1;
- char* p = (char*)&a;
- return *p;
- }
-
- int main()
- {
- int ret = check();
- if (ret == 1)
- {
- printf("小端\n");
- }
- else
- {
- printf("大端\n");
- }
- return 0;
- }
- #include<stdio.h>
-
- int main()
- {
- char a = -1;
- //-1的原码:10000000000000000000000000000001
- //-1的反码:11111111111111111111111111111110
- //-1的补码:11111111111111111111111111111111
- signed char b = -1;
- //b的补码与a相同
- unsigned char c = -1;
- //c也是与a相同
- printf("a = %d,b = %d,c = %d", a, b, c);
- return 0;
- }
解析:
内存中存的是补码
char 有一个字节,等于 8 个比特位,-1是有 32 个比特位,将 -1 存到 a 中,a 是 char 类型,a 里面只能存 -1 补码的低 8 位。
11111111
signed char 是一个有符号的 char ,所以和 a 一样,b 里面只能存 11111111
unsigned char 是一个无符号的 char ,但它也是个 char ,c 也只能存 11111111。
要通过 %d 打印一个整型,这里会发生整型提升,因为是有符号位,所以高位要补符号位
11111111111111111111111111111111
这 32 个 1 是补码, %d 打印的是原码,也就是打印 -1 , a 也就等于 -1 , b 与 a 相同。
unsigned char 是无符号的 char ,高位补的是 0
00000000000000000000000011111111
高位是 0 表示它是整数,整数原反补相同
转化为十进制打印也就是 255
补充:
char 到底是 signed char 还是 unsigned char ?
''C语言标准并没有规定,取决于编译器
int 是 signed int
short 是 signed short
结果:
a=-1,b=-1,c=255
- #include<stdio.h>
-
- int main()
- {
- char a = -128;
- //-128的原码:1000000000000000000000010000000
- //-128的反码:1111111111111111111111101111111
- //-128的补码:1000000000000000000000010000000
- printf("%u", a);
- return 0;
- }
解析:
a是一个 char 类型,只能存8个比特位。
10000000
%u 打印要发生整型提升,因为是有符号的 char,高位补符号位。
11111111111111111111111110000000
%u 打印一个无符号整型,无符号表示是整数,原反补相同,此时的补码就是原码,转化为十进制后输出结果
如果是以 %d 打印,%d 是打印有符号整数,回通过计算得到原码,最后输出 -128 。
结果:
4294967168
- #include<stdio.h>
-
- int main()
- {
- char a = 128;
- //128的原码:1000000000000000000000010000000
- //因为是正数。原反补相同
- printf("%u", a);
- return 0;
- }
解析:
char 类型只能存8个比特位
10000000
因为是有符号的 char,%u 打印,整型提升,高位补符号位
11111111111111111111111110000000
%u 打印无符号整数,原反补相同,转化为十进制
补充:
char 类型变量的取值范围
结果:
4294967168
-
- #include<stdio.h>
-
- int main()
- {
- int i = -20;
- //-20的原码:10000000000000000000000000010100
- //-20的反码:11111111111111111111111111101010
- //-20的补码:11111111111111111111111111101100
- unsigned int j = 10;
- printf("%d\n", i + j);
- return 0;
- }
解析:
10是整数,原反补相同
00000000000000000000000000001010
i的补码 + j的补码:
i:11111111111111111111111111101100
j:00000000000000000000000000001010
i + j 的补码:11111111111111111111111111110110
因为以 %d 打印,转化为原码后为
10000000000000000000000000001010
转化为十进制输出结果
结果:
-10
- #include<stdio.h>
-
- int main()
- {
- unsigned int i;
- for (i = 9; i >= 0; i--)
- {
- printf("%u\n", i);
- }
- return 0;
- }
解析:
i是一个无符号整型,不可能为负数,最小是0,%u 打印一个无符号数,判断条件是大于等于0,i的值一直减小到0就不会继续减小了,也就无法跳出循环。
结果:
死循环
- #include<stdio.h>
-
- int main()
- {
- char a[1000];
- int i;
- for (i = 0; i < 1000; i++)
- {
- a[i] = -1 - i;
- }
- return 0;
- }
解析:
a[i]的值依次为-1 -2 -3......-127 -128 127 126 125......3 2 1 0 -1 -2 ...... -127 -128 127......
因为是char类型,能存的最大负数和最大整数依次是
-128和127
第3题有做详细介绍
结果:
255
- #include<stdio.h>
-
- unsigned char i = 0;
- int main()
- {
- for (i = 0; i <= 255; i++)
- {
- printf("hello world\n");
- }
- return 0;
- }
解析:
unsigned char 是无符号的 char,i 的范围只能是0~255,而判断条件是小于等于255,无法跳出。
结果:
死循环