C语言数据类型
数据类型
整型数据类型
C语言提供了char、short、int以及long三种不同长度的整型数,并根据数据的表示是否带有符号位,又进一步区分为无符号整型数和有符号整型数。
整型数的表示
对于无符号整型数,数据在计算机中的表示就是普通的二进制数;但是有符号数由于包含符号位,需要使用额外的bit位来表示符号信息。最常见的有符号数的计算机表示方式就是补码。
有符号数的其它表示:
- 原码:最高有效位作符号位,用来确定剩下的位应该取负权还是正权
- 反码:
字节序
对于包含多个字节的整型数,一般都是被存储为连续的字节序列,但是不同的硬件体系,对于整数是从数据的高位还是低位开始存储又存在分歧,导致了在一些场景下,如网络数据传输,我们不得不关注字节序这个问题。字节序分为两种:
- 小端法:在内存中,数据按照最低有效字节到最高有效字节的顺序进行存储,即数据的高位在高地址处,低位在低地址处。
- 大端法:与小端法恰恰相反,其将最高有效字节存储到内存低地址。通常网络字节序都是采用的大端法。
以一个简单的整型数0x12345678为例,可以查看其在使用小端法和大端法存储时的差异:
整型数的大小
C语言提供了三种不同长度的整数:short、int和long型,但是却没有明确定义这三种整型数的长度。ANSI标准要求long型整数的长度至少应该是32位,short型和int型整数的长度至少应该是16位,而实际的长度需要根据程序运行的硬件平台来确定,一般来说:
- 16位硬件下:short和int为16位长度,long为32位长度
- 32位硬件下:short为16位长度,int和long为32位长度
- 64位硬件下:short为16位长度,int为32位长度,long则扩展至64位长度
没有固定长度数据类型是现代C语言的一个不完美的地方,因此后续C99标准,通过增加stdint.h和inttypes.h头文件,提供了明确长度的数据类型,从而稍稍弥补了这一不足。
字符类型
C语言提供了单独的关键字char来表示字符类型,但是从技术实现来说,字符类型本质还是整型数,只是在逻辑上了根据字符编码表做了一层转换。C语言在设计之初,仅支持ASCII编码标准字符,这是一个7位的编码标准,使用8位长度的整数即可容纳,因此C语言中的字符在大多数现代编译器中都被实现为8位整型数。
字符是有符号还是无符号
由于ANSI字符标准定义的字符范围是0-127,因此无论使用8位的无符号数或者有符号数都足以容纳这个范围,并且C语言标准也没有约束要使用哪种方式,因此具体行为也就取决于各种编译器的实现了。常见的编译器对字符类型的表示规定如下:
- VC编译器:规定char为signed char类型
- GCC编译器:x86体系下,规定char为signed char类型;ARM体系下规定char为unsigned char类型
8位整型数
在此需要特别说明的是,C语言并没有像Java那样为8位长度的整型数定义单独的关键字,因此我们只能使用字符类型char来表示。虽然意义稍有不合,却也别无他法,毕竟从数据表示的角度来说,这并没有任何差异。但是个人在此的建议是在使用时要区分char和unsigned char这两种类型:
- 当在具有明确字符含义的场景下,如字符串操作,使用char类型
- 在涉及单纯内存数据操作时,如内存拷贝,由于内存存储的字节本身没有正负的概念,可使用unsigned char类型进行表示
确保自己的使用行为是明确的,往往可以避免踩坑。
void类型
void定义为空类型,一般来说是无法在程序里定义一个void类型的变量,即使可以,也毫无意义。void比较常见的两种用法:
- 一种是定义“void *”类型的指针,这种类型的指针可以指向任何类型的数据,同时也可以转换为其它明确类型的指针
- 另一种是对函数的修饰,用于表明函数返回空类型或者函数不接受任何参数
相关参考
- 《C语言深度剖析》
- 《深入理解计算机系统》