1. 数据类型介绍
前面我们已经学习了基本的内置类型:
char // 字符数据类型
short // 短整型
int // 整形
long // 长整型
long long // 更长的整形
float // 单精度浮点数
double // 双精度浮点数
//C 语言有没有字符串类型?
以及他们所占存储空间的大小。
C99之前没有 longlong
int 在16位操作系统下 占2字节 32位 4字节 64位 4字节 (VS)
在新的标准下还有long double这样的类型
布尔类型 _Bool 是用来表示真假的,早期人们是用 1 0 来表示真假 现在:
定义了ture(1) 和 false(0) 其实本质上_Bool 本质上就是 int 的重命名
当然用时要有头文件
我们一般说的int long 都是 unsigned int(long),short也是。但是对于char
是没有规定是 signed char 还是 unsigned char ,但是常见的编译器里面我们用
的时候他是signed char。
类型的意义:
1. 使用这个类型开辟内存空间的大小(大小决定了使用范围)。
2. 如何看待内存空间的视角。
1.1 类型的基本归类
整形家族:
char
unsigned char
signed char
short
unsigned short [ int ]
signed short [ int ]
int
unsigned int
signed int
long
unsigned long [ int ]
signed long [ int ]
当我们打印有符号时应该用%d打印,用无符号时应该用%u
这里虽然是-10,但是我们是用%d来解析,就是有符号
这里我们改为%u:
大家看下图就很好理解了
也就是说一开始的数字先放入先前开辟的空间当中同时转化为二进制数,然后再存储到内存中时才会看类型来看是有符号还是无符号,有符号就看符号位,无符号就直接把存进去的补码当成源码。
浮点数家族:
float
double
构造类型:
> 数组类型
> 结构体类型 struct
> 枚举类型 enum
> 联合类型 union
构造类型也叫自定义类型,比如int arr【10】 和 int arr【5】 就是两种类型,我们把函数名这里是arr除去,留下的就是类型名,这里是int 【10】 和 int 【5】 ,所以是自定义类型。
指针类型
int *pi;
char *pc;
float* pf;
void* pv;
空类型:
void 表示空类型(无类型)
通常应用于函数的返回类型、函数的参数、指针类型。
2. 整形在内存中的存储
我们之前讲过一个变量的创建是要在内存中开辟空间的。空间的大小是根据不同的类型而决定的。
那接下来我们谈谈数据在所开辟内存中到底是如何存储的?
比如:
int a = 20 ;
int b = - 10 ;
我们知道为 a 分配四个字节的空间。
那如何存储?
下来了解下面的概念:
2.1 原码、反码、补码
计算机中的整数有三种表示方法,即原码、反码和补码。
三种表示方法均有 符号位 和 数值位 两部分,符号位都是用 0 表示 “ 正 ” ,用 1 表示 “ 负 ” ,而数值位 。
负整数的三种表示方法各不相同。
原码
直接将二进制按照正负数的形式翻译成二进制就可以。
反码
将原码的符号位不变,其他位依次按位取反就可以得到了。
补码
反码 +1 就得到补码。
正数的原、反、补码都相同。
对于整形来说:数据存放内存中其实存放的是补码。
为什么呢?
在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统 一处理;
同时,加法和减法也可以统一处理( CPU 只有加法器 )此外,补码与原码相互转换,其运算过程 是相同的,不需要额外的硬件电路。
我们看看在内存中的存储:
整数在内存中存的是补码,这是为什么呢?
这是因为:
这里同时补充一下源码求补码的两种方法:
法一:就是我们通识的源码得到反码就是符号位不变其他位按位取反然后反码得到补码就是反码加一。由补码得到源码就是逆着回去。
法二:这是作者比较喜欢用的。其实我们由补码得到源码一样可以按源码得到补码的方法,也就是说可以补码符号位不变,其他位按位取反得到反码,然后反码加一得到源码。这很神奇,大家可以自行验证哈!
然后接着正文:
我们可以看到对于a和b分别存储的是补码。但是我们发现顺序有点不对劲。
这是又为什么?
2.2 大小端介绍
什么是大端小端:
大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地址中。
为什么有大端和小端:
为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元 都对应着一个字节,一个字节为8 bit 。但是在 C 语言中除了 8 bit 的 char 之外,还有 16 bit 的 short 型, 32 bit 的 long 型(要看具体的编 译器),另外,对于位数大于 8 位 的处理器,例如 16 位或者 32 位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如 何将多个字节安排的问题。因此就 导致了大端存储模式和小端存储模式。
例如:一个 16bit 的 short 型 x ,在内存中的地址为 0x0010 , x 的值为 0x1122 ,那么 0x11 为 高字节, 0x22 为低字节。对于大端 模式,就将 0x11 放在低地址中,即 0x0010 中, 0x22 放在高地址中,即 0x0011 中。小端模式, 刚好相反。我们常用的 X86 结构是 小端模式,而 KEIL C51 则为大端模式。很多的 ARM , DSP 都为小端模式。有些 ARM 处理器还可以 由硬件来选择是大端模式还是小端 模式。
百度2015年系统工程师笔试题:
请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。
#include <stdio.h> int check_sys() { int i = 1; return (*(char *)&i); } int main() { int ret = check_sys(); if(ret == 1) { printf("小端\n"); } else { printf("大端\n"); } return 0; }