C语言数据类型

数据类型

C语言数据类型

整型数据类型

C语言提供了char、short、int以及long三种不同长度的整型数,并根据数据的表示是否带有符号位,又进一步区分为无符号整型数和有符号整型数。

整型数的表示

对于无符号整型数,数据在计算机中的表示就是普通的二进制数;但是有符号数由于包含符号位,需要使用额外的bit位来表示符号信息。最常见的有符号数的计算机表示方式就是补码。

有符号数的其它表示:

  1. 原码:最高有效位作符号位,用来确定剩下的位应该取负权还是正权
  2. 反码:

字节序

对于包含多个字节的整型数,一般都是被存储为连续的字节序列,但是不同的硬件体系,对于整数是从数据的高位还是低位开始存储又存在分歧,导致了在一些场景下,如网络数据传输,我们不得不关注字节序这个问题。字节序分为两种:

  • 小端法:在内存中,数据按照最低有效字节到最高有效字节的顺序进行存储,即数据的高位在高地址处,低位在低地址处。
  • 大端法:与小端法恰恰相反,其将最高有效字节存储到内存低地址。通常网络字节序都是采用的大端法。

以一个简单的整型数0x12345678为例,可以查看其在使用小端法和大端法存储时的差异:
C语言数据类型

整型数的大小

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.hinttypes.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语言深度剖析》
  • 《深入理解计算机系统》