一、数据类型介绍
前面我们已经学习了基本的内置类型:
char //字符数据类型
short //短整型
int //整型
long //长整型
long long //更长的整型
float //单精度浮点型
double //双精度浮点型
以及它们所占用存储空间的大小。
类型的意义:
- 使用这个类型,则开辟规定大小的存储空间。
- 存储空间在内存中的定位。
二、类型的基本归类
整型家族:
char
unsigned char //无符号char类型
signed char
short
unsigned short [int]
signed short [int]
int
unsigned int
signed int
long
unsigned long [int]
signed long [int]
浮点数家族:
float
double
构造类型:
数组类型
结构体类型 struct
枚举类型 enum
联合类型 union
指针类型:
int *pi;
char *pc;
float* pf;
void* pv;
空类型:
void 表示空类型
通常应用于函数的返回类型、函数的参数、指针类型。
三、整型在内存中的存储
一个变量的创建是需要在内存中开辟空间存储的。 空间的大小是根据不同的类型而决定。
接下来我们谈谈数据是如何存储的 eg:
int a = 20;
int b = -10;
我们都知道 int 为 a 分配四个字节的空间。那么要如何存储?
3.1 原码、反码、补码
- 计算机中有符号数有三种表示方式,即原码、反码、补码。
- 三种表示方式均有符号位和数值位两部分,符号位使用0表示“正”,用1表示“负”;而数值位三种表示方法各不相同。
- 原码:直接将数据翻译成二进制就可以。
- 反码:原码的符号位不变,其它位依次取反即可。
- 补码:反码+1可得到补码。
- 正数的原码、反码、补码都相同。
3.2 对于整型来说,数据在内存中存储的格式是补码。
为什么呢?
在计算机系统中,数值一律用补码来表示和存储。
原因是,使用补码可以将符号位和数值域统一处理。 同时,加法和减法也可以统一处理(CPU只有加法器)。 补码和原码相互转换,运算过程是相同的,都可以取反加一得到彼此。
我们也可以举个例子来证明:
在计算机中没有减法器,但是我们可以让正数加上负数,来进行减法操作。
eg:1 + (-1)
//1 正数原码、反码、补码相同
//原码:00000000000000000000000000000001
//反码:00000000000000000000000000000001
//补码:00000000000000000000000000000001
//-1
//原码:10000000000000000000000000000001
//反码:11111111111111111111111111111110
//补码:11111111111111111111111111111111
我们观察原码,如果我们使用原码来进行 1+(-1) 会得到什么?
会得到 -2,这明显不是 1+(-1) 的结果。
如果我们使用补码来操作,结果就是 0。
四、大小端介绍
什么是大小端?
大端字节序: 把数据的低位字节序的内容存放在高地址处,高位字节序的内容存放在低地址处。
小端字节序: 把数据的低位字节序的内容存放在低地址处,高位字节序的内容存放在高地址处。 而数据到底是按照大端还是小端存储,要看编译器的设置。。。
那么如何用段代码来查看编译器是大端还是小端?
我们数值取一,然后取地址存储到指针类型char中。
我们只需要查看指针类型char中的第一个数据,是1则是小端字节序,是0则是大端字节序。
int main() {
int a = 1;
char* pi = (char*)&a;
if (*pi == 1) {
printf("小端\n");
}
else {
printf("大端\n");
}
return 0;
}
也可以写成函数,进行优化…
int check_sys() {
int a = 1;
char* p = (char*)&a;
return *p;
}
int main() {
int ret = check_sys();
if (ret == 1) {
printf("小端\n");
}
else {
printf("大端\n");
}
return 0;
}
五、来亿点练习题
①练习题
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;
}
答案:-1, -1, 255 解析: a,b,c 的补码都是一样的 1111 1111。 但是我们看待的不同,a 和 b 首位是符号位,1 表示是负数;而 c 是无符号整型,首位还是数据 1。 最后在输出时,%d是按照 int 形式输出,要整型提升,a 和 b 都是看符号位提升直接补齐 1;而 c 的整型提升因为没有符号位,直接补齐 0。导致最后结果不一样。
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;
}
②练习题
int main() {
char a = -128;
printf("%u\n", a);
return 0;
}
答案:4294967168 解析:
int main() {
char a = -128;
printf("%u\n", a);
return 0;
}
③练习题
int main() {
char a = 128;
printf("%u\n", a);
return 0;
}
答案:4294967168 解析:
int main() {
char a = 128;
printf("%u\n", a);
return 0;
}
char 类型内存存储。 127 再加 1 会变成 -128。 之后的 -127,-126都有迹可循,但是 -128 会复杂一些,需要查看补码反码原码。
④练习题
int main() {
int i = -20;
unsigned int j = 10;
printf("%d\n", i + j);
return 0;
}
答案:-10 解析:
int main() {
int i = -20;
unsigned int j = 10;
printf("%d\n", i + j);
return 0;
}
⑤练习题
int main() {
unsigned int i;
for (i = 9; i >= 0; i--) {
printf("%u\n", i);
}
return 0;
}
答案:死循环 解析:
int main() {
unsigned int i;
for (i = 9; i >= 0; i--) {
printf("%u\n", i);
}
return 0;
}
⑥练习题
int main() {
char a[1000];
int i;
for (i = 0; i < 1000; i++) {
a[i] = -1 - i;
}
printf("%d", strlen(a));
return 0;
}
答案:255 解析:
int main() {
char a[1000];
int i;
for (i = 0; i < 1000; i++) {
a[i] = -1 - i;
}
printf("%d", strlen(a));
return 0;
}
⑦练习题
unsigned char i = 0;
int main() {
for (i = 0; i <= 255; i++) {
printf("hello world\n");
}
return 0;
}
答案:死循环 解析:
unsigned char i = 0;
int main() {
for (i = 0; i <= 255; i++) {
printf("hello world\n");
}
return 0;
}
|