C语言中,数据类型包括:基本类型(整型、浮点型、字符型),复合类型(数组、结构体、联合体、枚举),指针类型。这篇笔记我们介绍C语言中基本数据类型相关的知识,有关复合数据类型和指针将在后续章节介绍。
数据类型是对数据的抽象,相同类型的数据有相同的表示形式、存储格式以及相关操作。编程语言中所有的数据都必定属于某种类型。可以这样简单的理解:数据类型就是创建变量的模具。
C语言中,整型包括char
,short
,int
,long int
(简写为long
),long long int
(简写为long long
),signed
和unsigned
表示有符号数或无符号数。八进制数以0
开头,十六进制以0x
开头,字面值结尾加u
表示unsigned
,加L
表示long
。
整型的长度可参考下表。
类型 | ILP32 | LP64 |
---|---|---|
char | 8 | 8 |
short | 16 | 16 |
int | 32 | 32 |
long | 32 | 64 |
long long | 64 | 64 |
指针 | 32 | 64 |
注:ILP32/LP64指Intel x86/64平台,Linux,gcc编译器。
C语言中,浮点型包括float
,double
,long double
。IEEE754标准中,float
为32位,double
为64位,long double
则平台差异较大,不能一概而论。
C语言中,类型转换可以分为隐式类型转换和强制类型转换。其中,隐式转换虽然规则看起来很复杂,但实际使用时并不需要考虑太多,下面我们简单介绍。
在一个表达式中,凡是可以使用int
或unsigned int
类型做右值的地方也都可以使用有符号或无符号的char
类型、short
类型。如果原始类型的取值范围都能用int
类型表示,则其类型被提升为int
,如果原始类型的取值范围用int
类型表示不了,则提升为unsigned int
型,这称为Integer Promotion(整型提升)。
整型提升只影响上述几种类型的值,对其它类型无影响。C99规定整型提升适用于以下几种情况:
...
,那么调用函数时要对相应的实参做整型提升。此外,相应的实参如果是float
类型的也要被提升为double
类型,这条规则称为Default Argument Promotion(默认参数提升)。char
型、short
型在做算术运算之前首先要做整型提升,然后才能参与计算。例:unsigned char c1 = 255, c2 = 2;
int n = c1 + c2;
long double
,则把另一边也转成long double
。double
,则把另一边也转成double
。float
,则把另一边也转成float
。a
和b
做整型提升,如果类型仍不相同,则需要继续转换。首先我们规定char
、short
、int
、long
、long long
的转换级别( Integer Conversion Rank) 一个比一个高,同一类型的有符号和无符号数具有相同的Rank。转换规则如下:unsigned int
和unsigned long
做算术运算时都转成unsigned long
。unsigned long
和int
做算术运算时都转成unsigned long
,unsigned long
和long
做算术运算时也都转成unsigned long
。unsigned int
和long
在做算术运算时都转成long
。unsigned int
和long
在做算术运算时都转成unsigned long
。如果赋值或初始化时等号两边的类型不相同,则编译器会把等号右边的类型转换成等号左边的类型再做赋值。函数参数、返回值也是赋值的过程,也是同理的。
例如计算表达式(double)3 + i
,首先将整数3
强制转换成double
型(值为3.0
),然后和整型变量i
相加,这时适用Usual Arithmetic Conversion规则,首先把i
也转成double
型,然后两者相加,最后整个表达式也是double
型的。
现在要把一个M位的类型(值为X)转换成一个N位的类型,所有可能的情况如下表所示。实际上下图中容易出错的做法很少出现,全部转换不需要记住,遇到bug能想到这方面现查即可。
typedef
可以给一个数据类型起别名,下面是一个例子。
typedef unsigned int u32;
typedef struct complex_struct
{
double x, y;
} complex_struct;
代码中,我们给unsigned int
起了别名u32
,给struct complex_struct
起了别名complex_struct
,使用这些数据类型声明变量时我们可以直接使用别名。
注意:不要滥用别名!过度使用别名是一种画蛇添足的行为,不仅不会提升代码可读性,反而会严重降低代码可读性。
C语言中有一种特殊的“空”类型void
,它也有对应的指针类型void *
(参考指针相关章节)。void
类型单独使用没有意义,它的意义在于对函数参数和函数返回进行限定。
void printMessage(void)
{
printf("Hello, world!\n");
}
参数中的void
表示该函数不接受任何参数,返回值中的void
表示该函数不返回任何值。
sizeof
是一个特殊的运算符,它能返回变量或类型在内存中分配空间时分配的字节数。
#include <stdio.h>
int main(void)
{
printf("%zu\n", sizeof(int));
printf("%zu\n", sizeof 1);
return 0;
}