C 数据类型
C 是强类型语言,每个变量都必须先声明类型才能用。C 的数据类型主要分四大类:基本类型(整数、浮点、字符)、枚举类型(enum)、void 类型(无值)、派生类型(指针、数组、结构体、联合)。本篇聚焦最常用的基本类型——这是写任何 C 程序的基石。
一、整数类型
整数是 C 里用得最多的类型。C 提供了不同大小的整数,以适配不同的存储需求:
#include <stdio.h>
#include <limits.h> // 各类型取值范围
int main(void) {
// 整数类型(从小到大)
short s = 100; // 短整型,通常 2 字节
int i = 1000; // 整型,通常 4 字节(最常用)
long l = 100000L; // 长整型,32/64 位(末尾 L)
long long ll = 1000000LL; // 更长整型(C99),至少 8 字节
// signed / unsigned
unsigned int u = 4000000000U; // 无符号,最高位不当符号位
// 0 ~ 4294967295(对 32 位 int)
printf("int 范围: %d ~ %d\n", INT_MIN, INT_MAX);
printf("unsigned int 最大: %u\n", UINT_MAX);
printf("long 最大: %ld\n", LONG_MAX);
return 0;
}各整数类型占的字节数(典型值,Linux/macOS 64 位系统):
- char:1 字节(8 位),范围 -128 ~ 127 或 0 ~ 255
- short:2 字节,范围 -32768 ~ 32767
- int:4 字节,范围约 ±21 亿(最常用)
- long:Linux/macOS 64 位下 8 字节,Windows 64 位下 4 字节(注意!)
- long long(C99):至少 8 字节,范围约 ±9.2 × 1018
signed / unsigned:每个整数类型都有有符号(signed,默认)和无符号(unsigned)两个版本。unsigned 把符号位也用来存数据,所以能存两倍的正数,但不能存负数。
二、浮点类型
浮点数用来表示带小数的数,采用 IEEE 754 标准存储:
#include <stdio.h>
#include <float.h> // 浮点数取值范围/精度
int main(void) {
// 浮点类型
float f = 3.14f; // 单精度,通常 4 字节(末尾 f)
double d = 3.141592653589; // 双精度,通常 8 字节(默认)
long double ld = 3.14159265358979323846L; // 扩展精度(末尾 L)
// 注意:浮点数有精度损失!
printf("%.20f\n", 0.1 + 0.2); // 0.30000000000000004484...
// 浮点数不要直接用 == 比较!
printf("float 精度位数: %d\n", FLT_DIG); // 通常 6
printf("double 精度位数: %d\n", DBL_DIG); // 通常 15
printf("float 最大: %e\n", FLT_MAX);
return 0;
}- float:4 字节,精度约 6~7 位有效数字(末尾要加
f,否则默认是 double)。 - double:8 字节,精度约 15~16 位(默认浮点类型)。
- long double:16 字节(平台相关),更高精度。
重要警告:浮点数有精度损失(0.1 + 0.2 不等于 0.3!),所以永远不要用 == 直接比较两个浮点数,应该判断差的绝对值是否小于某个阈值(如 1e-9)。
三、字符类型 char
C 里没有真正的"字符"类型——char 本质上就是一个字节的小整数。它存的字符其实是 ASCII 码值:
#include <stdio.h>
#include <ctype.h> // 字符处理函数
int main(void) {
char grade = 'A'; // 单字符用单引号
char newline = '\n'; // 转义字符也是 char
char num = '7';
// char 本质是小整数(0~127 是 ASCII)
printf("%c 的 ASCII 码是 %d\n", grade, grade); // A 的 ASCII 是 65
printf("%c 的 ASCII 码是 %d\n", '0', '0'); // 0 的 ASCII 是 48
// 字符运算
char lower = grade + 32; // 大写转小写(A=65, a=97)
printf("小写: %c\n", lower); // a
// ctype.h 提供的字符判断函数
printf("isalpha('A') = %d\n", isalpha('A')); // 非0(真)
printf("isdigit('7') = %d\n", isdigit('7')); // 非0(真)
printf("toupper('a') = %c\n", toupper('a')); // A
return 0;
}几个要点:
- 字符字面量用单引号
'A'(字符串才用双引号"A")。 char既能用%c当字符打印,也能用%d当整数打印。- 大小写转换:'A'=65,'a'=97,差 32;大写转小写加 32,反之减 32。
- 中文等多字节字符不能用单个 char 表示,需要多字节编码或 wchar_t。
四、sizeof 运算符
sizeof 是 C 里一个特殊的运算符(不是函数),它返回某类型或变量占的字节数。它在编译期就计算好,不占运行时间。
#include <stdio.h>
#include <limits.h>
int main(void) {
// sizeof 返回某类型/变量占的字节数
printf("char: %zu\n", sizeof(char)); // 1(恒为 1)
printf("short: %zu\n", sizeof(short)); // 通常 2
printf("int: %zu\n", sizeof(int)); // 通常 4
printf("long: %zu\n", sizeof(long)); // Linux64=8, Win64=4
printf("float: %zu\n", sizeof(float)); // 通常 4
printf("double: %zu\n", sizeof(double)); // 通常 8
printf("指针: %zu\n", sizeof(int*)); // 32位系统=4, 64位=8
// sizeof 是运算符,不是函数
// 编译期就计算好了,不占运行时间
int arr[10];
printf("数组大小: %zu\n", sizeof(arr)); // 40
printf("元素个数: %zu\n", sizeof(arr)/sizeof(arr[0])); // 10
// %zu 是 size_t 的占位符(C99)
return 0;
}用 sizeof 求数组元素个数是 C 里的经典技巧:sizeof(arr) / sizeof(arr[0])。注意 sizeof 返回的类型是 size_t(无符号),打印用 %zu(C99)。
五、类型转换
不同类型的值一起运算时,C 会自动做类型转换。转换分两种:
#include <stdio.h>
int main(void) {
// 1. 隐式转换(自动):小类型 → 大类型,安全
int i = 100;
double d = i; // int → double,自动
printf("%f\n", d); // 100.000000
// 2. 隐式转换(自动):大类型 → 小类型,可能丢精度!
double pi = 3.14159;
int truncated = pi; // double → int,直接截断小数
printf("%d\n", truncated); // 3
// 3. 强制转换(显式):(目标类型)值
int a = 10, b = 3;
double result = (double)a / b; // 先把 a 转成 double,再除
printf("%f\n", result); // 3.333333
// 不转换的对照
printf("%d\n", a / b); // 3(整数除法,丢小数)
// 4. 数据丢失示例
long big = 3000000000L;
int small = (int)big; // 溢出,得到的是错的值
printf("big=%ld, small=%d\n", big, small);
return 0;
}隐式转换规则(向上提升):char → int → long → long long → float → double → long double。小类型会自动提升成大类型参与运算,不会丢精度;反过来(大变小)则可能丢数据。
强制转换语法:(目标类型)值。注意 C 的强制转换不像 C++ 那样有 static_cast 等多种,它就一种语法,所以要格外小心——编译器不会再帮你检查。
六、转义字符
有些字符无法直接写在源码里(如换行、引号),需要用转义字符(反斜杠开头)表示:
// C 常用转义字符
\n 换行 \t 制表符
\r 回车 \\ 反斜杠 \
\' 单引号 \" 双引号
\0 空字符(NULL) \a 警报(响铃)
\b 退格 \f 换页
\x41 十六进制表示字符 'A'
\101 八进制表示字符 'A'最常用的包括换行符(用于打印换行)、制表符(对齐输出)、字面反斜杠本身,以及字符串结束符 NUL(后续字符串篇会重点讲)。具体写法见下面的代码示例。
七、limits.h 与 float.h
不同平台上类型的取值范围可能不同,标准库 <limits.h> 和 <float.h> 提供了这些常量:
INT_MIN/INT_MAX:int 的最小/最大值UINT_MAX:unsigned int 最大值LONG_MIN/LONG_MAX:long 的最小/最大值CHAR_BIT:一字节的位数(通常 8)FLT_MAX/DBL_MAX:float/double 最大值FLT_DIG/DBL_DIG:float/double 有效数字位数
写跨平台代码时,不要假设 int 一定是 4 字节,用 sizeof 或这些宏来判断更稳妥。
八、stdint.h(C99 固定宽度类型)
因为 int/long 在不同平台大小不一致,C99 引入了固定宽度整数类型(<stdint.h>):
int8_t/uint8_t:固定 8 位int16_t/uint16_t:固定 16 位int32_t/uint32_t:固定 32 位int64_t/uint64_t:固定 64 位
写需要精确控制大小的代码(网络协议、二进制文件)时,优先用这些类型,避免平台差异。
小结
记住:int 是最常用的整数(4 字节)、double 是默认浮点(8 字节)、char 是字符也是小整数。sizeof 在编译期算字节数。整数和浮点互相转换有规则,但浮点别用 == 比较。下一篇我们看 C 的运算符——如何操作这些数据。
← 上一篇 C 变量
下一篇 C 运算符 →