第一:数据类型分类
1.1 基本内置类型
类型 |
别名 |
所占字节 |
解释 |
char |
signed char |
1 |
字符数据 |
short |
signed short [int] |
2 |
短整型 |
int |
signed [int] |
4 |
整型 |
long |
signed long [int] |
4 |
长整型 |
long long |
signed long long [int] |
8 |
长长整型 |
float |
- |
4 |
单精度浮点型 |
double |
- |
8 |
双精度浮点型 |
long double |
- |
8 |
长双精度浮点型 |
#include <stdio.h>
int main()
{
printf("char %d\n", sizeof(char));
printf("short %d\n", sizeof(short));
printf("int %d\n", sizeof(int));
printf("long %d\n", sizeof(long));
printf("long long %d\n", sizeof(long long));
printf("float %d\n", sizeof(float));
printf("double %d\n", sizeof(double));
printf("long double %d\n", sizeof(long double));
return 0;
}

1.2 取值范围
类型 |
最小值 |
最大值 |
最小值 |
最大值 |
char |
-2^7 |
2^7-1 |
SCHAR_MIN:-128 |
SCHAR_MAX:127 |
unsigned char |
0 |
2^8-1 |
0 |
UCHAR_MAX:0xff/255 |
short |
-2^15 |
2^15-1 |
SHRT_MIN:-32768 |
32767 |
unsigned short |
0 |
2^16-1 |
0 |
USHRT_MAX:0xffff/65535 |
int |
-2^31 |
2^31-1 |
INT_MIN:-2147483648 |
INT_MAX:2147483647 |
unsigned int |
0 |
2^32-1 |
0 |
UINT_MAX:0xffffffff/4294967295 |
long |
-2^31 |
2^31-1 |
LONG_MIN:-2147483648L |
LONG_MAX:2147483647L |
unsigned long |
0 |
2^32-1 |
0 |
ULONG_MAX:0xffffffffUL/4294967295L |
long long |
-2^63 |
2^63-1 |
LLONG_MIN:-9223372036854775807i64 - 1 |
LLONG_MAX:9223372036854775807i64 |
unsigned long long |
0 |
2^64-1 |
0 |
ULLONG_MAX:0xffffffffffffffffui64 |
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("char min and max = %d\t\t%d\n", SCHAR_MIN, SCHAR_MAX);
printf("unsigned char min and max = %d\t\t%d\n", 0, UCHAR_MAX);
printf("short min and max = %d\t\t%d\n", SHRT_MIN, SHRT_MAX);
printf("unsigned short min and max = %d\t\t%d\n", 0, USHRT_MAX);
printf("int min and max = %d\t\t%d\n", INT_MIN, INT_MAX);
printf("unsigned int min and max = %d\t\t%#x\n", 0, UINT_MAX);
printf("long min and max = %ld\t\t%ld\n", LONG_MIN, LONG_MAX);
printf("unsigned long min and max = %d\t\t%#x\n", 0, ULONG_MAX);
printf("long long min and max = %lld\t\t%lld\n", LLONG_MAX, LLONG_MAX);
printf("unsigned long long min and max = %d\t\t%llu\n", 0, ULLONG_MAX);
return 0;
}

1.3 构造数据
类型 |
关键字 |
数组 |
[] |
结构体 |
struct |
联合体 |
union |
枚举 |
enum |
1.4 指针和空类型
指针类型是指在类型后面加上一颗*,表示,好比:int* p;表示p是一个整型指针,指向的内存空间为int。
空指针:void *,好比内存函数:malloc calloc等函数的返回值都为void*类型,须要强制将其转化为指定类型的指针,如:int arr = (int*)malloc(10 * sizeof(10)),即申请了10个int的内存空间。
第二:整型的存储方式
2.1 存储方式:
整型数据在内存中是以补码的方式进行存储的。
整型:算法
- 有符号位的整型
1.1. 正数:原码=反码=补码
1.2. 负数:反码=原码的除符号位以外,其他位取反,补码 = 反码+1
- 无符号位整型:原码=反码=补码
2.2 大小端存储方式
是指字节在内存中存放的顺序。
分为大端存储(大端字节存储)和小端存储(小端字节存储)
Column 1 |
内存低地址 |
内存高地址 |
小端 |
数据补码的低位 |
数据补码的高位 |
大端 |
数据补码的高位 |
数据补码的低位 |
判断系统是以哪一种方式存放数据的。
以下面例子:
数组
// 小端:返回1,大端:返回0
int check_sys()
{
int a = 1;
char* p = (char*)&a;
if (1 == *p)
{
return 1;
}
else
{
return 0;
}
}
// 小端:返回1,大端:返回0
int check_sys_v1()
{
int a = 1;
char* p = (char*)&a;
return *p; // 由于*p == 1,返回1,*p == 0,返回0,因此直接返回*p
}
// 小端:返回1,大端:返回0
int check_sys_v2()
{
int a = 1;
return *(char*)&a; // 由于*p == 1,返回1,*p == 0,返回0,因此直接返回*p
}
int main()
{
int a = 1024;
int ret = check_sys_v2(a);
if (0 == ret)
{
printf("大端字节模式\n");
}
else
{
printf("小端字节模式\n");
}
return 0;
}

2.2.1 例1:
int main()
{
char a = -1; // 由于a是char类型,只占1个字节,且是小端字节存储模式,因此将-1的补码的低8位所占的字节上的值截取给char a:11111111
signed char b = -1; // signed char b 等价于char a
unsigned char c = -1; // c存的补码也是11111111,可是为无符号的整型,则原码=反码=补码,故原码为11111111,即255
// 11111111111111111111111111111111 - -1的补码
// 由于a是char类型,只占1个字节,且是小端字节存储模式,因此将存放在低地址中的a的低数据位中的8个比特位截取给a
// 故 a = 11111111 - 补码
// b是signed char 能够简写为char b,故与a数据类型相同
// 故 b = 11111111 - 补码
// 因为c也是char类型
// 故 c = 11111111 - 补码
// 由于打印时,是以整型进行打印的,因此须要作提高(按照原符号位进行提高)
// 因为a是有符号的,且符号位1,则补1,即为:11111111111111111111111111111111,
// 前24个1为补的1,则其原码为1000...0001,为-1
// b和a都为有符号的char,故他们相同
// c是无符号的char,则补0进行提高,即为00000000000000000000000011111111,其原码=反码=补码,故为255
printf("a = %d,b = %d,c = %d\n", a, b, c);
return 0;
}

2.2.2 例2:
int main()
{
char a = -128;
// 10000000 00000000 00000000 10000000 - 原码
// 11111111 11111111 11111111 01111111 - 反码
// 11111111 11111111 11111111 10000000 - 补码
// a 为char占一个字节:因此截取低地址所存取的值(数据的低位):10000000
// char a:10000000
// %u为无符号的整型,因此要作提高,因为char a为有符号,因此提高位补1:
// 11111111 11111111 11111111 10000000 (提高后),提高后为无符号,因此其原码=反码=补码其对应的十进制为;4294967168
printf("%u\n", a);
return 0;
}

2.2.3 例3:
int main()
{
char a = 128;
// 00000000 00000000 00000000 10000000 - 原码=反码=补码
// a 为char占一个字节:因此截取低地址所存取的值(数据的低位):10000000
// char a:10000000
// %u为无符号的整型,因此要作提高,因为char a为有符号,因此提高位补1:
// 11111111 11111111 11111111 10000000 (提高后),提高后为无符号,因此其原码=反码=补码其对应的十进制为;4294967168
printf("%u\n", a);
return 0;
}

2.2.4 例4:
int main()
{
//9 8 7 6 5 4 3 2 1 0 2^32-1 ...0 2 ^ 32 - 1 ...0往复进行死循环
// 由于当i==0时打印后,执行i--;即i = 0-1 = 0 + (-1) = 32个1
// i 为无符号整型,因此原码和补码相同,即i为2^32-1
unsigned int i;
for (i = 9; i >= 0; i--)
{
printf("%u\n", i);
}
}
2.2.5 例5:
int main()
{
char a[1000];
int i;
for (i = 0; i <= 1000; i++)
{
a[i] = -1 - i; // -1 -2 .. -128 127 126 ... 1 0 -1 ....
}
printf("%d\n", strlen(a)); // 遇到0中止
return 0;
}
unsigned char i = 0;
int main()
{
for (i = 0; i <= 255; i++)
{
printf("hello, world %d\n", i);0 .. 255 0 .. 255 ...死循环
}
return 0;
}
第三:浮点数在内存的存数形式
3.1 国际标准:
根据国际标准IEEE(电气和电子工程协会)754规定,能够将任何一个浮点数(二进制)表示为如下的通用形式:
3.1.1 公式:
(-1)^S * M * 2^E
注释:
1. (-1)^S表示符号位,负数:S = 1;正数:S = 0;
2. M:表明有效位数(科学计数法),1 <= M < 2;
3. 2^E:表明指数位数(E),如2^4,E = 4;
S M E存放顺序和大小:
(1)对于32位的浮点数:float(占4个字节,32个比特位)S M E的存放顺序和大小为:
低地址--->高地址:
S:存放第一位(1位);E:存放2-9位(8位);M:存放10-32位(23位)。
(2)对于64位的浮点数:double(占8个字节,64个比特位)S M E的存放顺序和大小为:
低地址--->高地址:
S:存放第一位(1位);E:存放2-12位(11位);M:存放13-64位(52位)。
3.2 浮点数转为二进制的算算法步骤:
(1)整数部分(除2):如:13:
13 / 2 = 6 ... 1
6 / 2 = 3 ... 0
3 / 2 = 1 ... 1
1 / 2 = 0 ... 1 # 当商为0时,中止运算,将一次获得的余数做为二进制的低位-->高位数据,如:13:1101
(2)小数部分(乘2):如0.875
0.875 * 2 = 1.750 = 1 + 0.75 # 二进制中的左边第一个1
0.75 * 2 = 1.50 = 1 + 0.5 # 二进制中左边第二个1
0.5 * 2 = 1.0 = 1 + 0 # 当相乘后小数位0,则中止计算将依次获得整数位做为小数二进制的高位-->低位,如:111
如:13.5的二进制为:00001101.1,即1101.1
将其转化为IEEE754标准:(-1) ^ 0 * 1.1011 * 2 ^ 3
即:S = 0;M = 1.1011;E = 3
3.3 S M E 在内存中存放的值
(1)S
若是为正数:S在内存中存放的是0
若是是负数:S在内存中存放的是1
(2)M
将M的小数部分存放在内存中。
(3)E
E是一个无符号正数;float(8为:0-255);double(11位:0-2047);
因为E能够是负数,当浮点数小于1时,因此存入内存中的E为真实的E加上一个中间数(double:1023;float:127),即:内存中E = 二进制E + 127 or 1023.
如:float的13.875的二进制:1.1011中的E为3,则内存中为3 + 127 = 128 + 2 = 10000010(2^7 + 2 ^ 1)
例如:
13.875在内存中的存放为:
二进制为:1101.111
IEEE754:(-1) ^ 0 * 1.101111 * 2 ^ 3, S = 0;M = 1.1011;E = 3
内 存 为:0 10000010 10111100000000000000000
:0100 0001 0101 1110 0000 0000 0000 0000
十六进制:41 5e 00 00,即:0x415e0000
内存为 : 00 00 5e 41(低地址-->高地址)

3.4 去读数据
(1)当E(内存中的E)中同时存在1和0
其值-127或者1023获得的是IEEE754中公式中的E。
内中的M中为小数(xxxx),将其加上1,变为1.xxxx
正数:S= 0;负数:S=1
(2)E(内存中的E)为全0 为一个无穷小的数字
真是的E为1-127 or 1 - 1023
M:不在加上正数部的1. 0.xxxx
S:同上
(3)E(内存中的E)为全1,若是有效数字全为0,则表示无穷大数字。
3.5 例子解析
int main()
{
// 00000000 00000000 00000000 00000110 - 6的补码
// 当以float输出时,上述为浮点数的补码,将其进行读取为:S = 0;E = 1 - 126;M = 0.11 为一个无穷小的数
int a = 6;
float* p = (float*)&a;
printf("a = %d\n", a); // 6
printf("*p = %f\n", *p); // 0.0000000
// 6.0的二进制:110.0 -->IEEE754: (-1)^0 * 1.10 * 2 ^ 2
// S = 0;M = 1.10;E = 2;2 + 127 = 10000001;
// 内存:01000000 11000000 00000000 00000000
// 因此当以整型进行输出时:为01000000 11000000 00000000 00000000,为正数,即为原码:
*p = 6.0;
printf("a = %d\n", a); // 01000000110000000000000000000000,十进制:1,086,324,736
printf("*p = %f\n", *p); // 6.0
return 0;
}
