- 变量的数据类型:这决定了变量需要存储什么样的数据(整数、小数、字符等),从而决定了它需要多少“空间”来容纳这些数据。
- 编译器和目标平台:不同的编译器和不同的计算机硬件(如32位 vs 64位系统)可能会对某些数据类型分配不同大小的内存。
下面我们详细分解这两个因素,并提供最准确的方法来查询实际大小。

(图片来源网络,侵删)
核心决定因素:数据类型
C语言为不同的数据类型定义了最小内存需求,但编译器可以根据目标架构提供更大的空间,以下是常见数据类型及其典型的内存大小。
基本数据类型
| 数据类型 | 典型大小 (32位系统) | 典型大小 (64位系统) | 描述 |
|---|---|---|---|
char |
1 字节 | 1 字节 | 存储单个字符(如 'A')或小整数。 |
short |
2 字节 | 2 字节 | 短整型。 |
int |
4 字节 | 4 字节 | 整型,这是最常用的整数类型。 |
long |
4 字节 | 8 字节 | 长整型。注意: 在64位Linux/Windows上通常是8字节,但在一些旧的32位系统或特定编译器上可能是4字节。 |
long long |
8 字节 | 8 字节 | 双长整型,保证至少8字节。 |
float |
4 字节 | 4 字节 | 单精度浮点数(小数)。 |
double |
8 字节 | 8 字节 | 双精度浮点数,精度更高。 |
long double |
8 或 16 字节 | 8 或 16 字节 | 扩展精度浮点数,大小不固定。 |
重要提示:
- 字节 是内存的基本单位,1字节等于8个比特,我们通常用
sizeof操作符来获取字节数。 sizeof是一个编译时操作符,而不是函数,它在编译时就能计算出结果。long类型的大小在不同平台上的差异是C语言中一个著名的“陷阱”。
指针类型
指针变量存储的是内存地址,指针的大小取决于CPU的寻址能力。
| 指针类型 | 典型大小 (32位系统) | 典型大小 (64位系统) | 描述 |
|---|---|---|---|
void* |
4 字节 | 8 字节 | 指向任意类型的通用指针。 |
int* |
4 字节 | 8 字节 | 指向一个整型变量的指针。 |
char* |
4 字节 | 8 字节 | 指向一个字符变量的指针。 |
double* |
4 字节 | 8 字节 | 指向一个双精度浮点变量的指针。 |
关键点:在同一个程序中,所有指针类型的大小通常是相同的,它们都足够大以存储系统的虚拟地址,在64位系统上,地址总线是64位的,所以指针大小是8字节。

(图片来源网络,侵删)
自定义类型 (结构体 struct 和联合体 union)
- 结构体 (
struct): 结构体的大小是其所有成员大小之和,但不一定等于简单相加,编译器为了提高内存访问效率,会进行内存对齐,这会导致结构体内部或末尾出现“空洞”或填充字节。struct Example { char c; // 1 byte int i; // 4 bytes }; // 简单相加是 5 bytes,但由于对齐,实际大小通常是 8 bytes。 // (char c) 占1字节,后面会填充3字节,(int i) 从4的倍数地址开始。 - 联合体 (
union): 联合体的大小是其最大成员的大小,因为联合体的所有成员共享同一块内存空间。
如何准确获取变量的大小:sizeof 操作符
不要凭记忆去猜测类型的大小,最可靠的方法是使用 sizeof 操作符。
语法
sizeof(type_name); // 获取类型或类型别名的大小 sizeof(variable_name); // 获取变量的大小
示例代码
#include <stdio.h>
int main() {
// 基本数据类型
printf("Size of char: %zu bytes\n", sizeof(char));
printf("Size of short: %zu bytes\n", sizeof(short));
printf("Size of int: %zu bytes\n", sizeof(int));
printf("Size of long: %zu bytes\n", sizeof(long));
printf("Size of long long: %zu bytes\n", sizeof(long long));
printf("Size of float: %zu bytes\n", sizeof(float));
printf("Size of double: %zu bytes\n", sizeof(double));
printf("Size of long double: %zu bytes\n\n", sizeof(long double));
// 指针类型
int a = 10;
double b = 20.5;
printf("Size of int*: %zu bytes\n", sizeof(int*));
printf("Size of double*: %zu bytes\n", sizeof(double*));
printf("Size of void*: %zu bytes\n\n", sizeof(void*));
// 变量
int var_int = 100;
char var_char = 'A';
printf("Size of variable var_int: %zu bytes\n", sizeof(var_int));
printf("Size of variable var_char: %zu bytes\n", sizeof(var_char));
// 结构体示例
struct Point {
int x;
int y;
};
struct Point p1;
printf("Size of struct Point: %zu bytes\n", sizeof(struct Point)); // 应该是 8 bytes
struct Mixed {
char c;
int i;
};
struct Mixed m1;
printf("Size of struct Mixed: %zu bytes\n", sizeof(struct Mixed)); // 可能是 8 bytes,而不是 5 bytes
return 0;
}
注意:printf 中使用 %zu 是为了正确打印 sizeof 返回的 size_t 类型,这是一种更安全和现代的做法。
内存对齐:为什么结构体大小不等于成员之和?
编译器进行内存对齐的主要目的是提高CPU访问内存的效率,CPU在读取内存时,通常是从特定地址(如4字节、8字节或16字节的倍数)开始读取的,如果数据没有对齐,CPU可能需要进行两次内存访问才能读/写一个完整的变量,这会严重影响性能。
规则简化:

(图片来源网络,侵删)
- 结构体的第一个成员放在偏移量为0的地址。
- 其他成员的偏移量必须是它自身大小的整数倍(或编译器默认对齐数的整数倍,取较小者)。
- 结构体的总大小必须是所有成员中最大大小的整数倍。
示例分析:
struct MyStruct {
char a; // size=1, offset=0
int b; // size=4, offset must be multiple of 4.
// So, after 'a' (at offset 0), we add 3 bytes of padding.
// 'b' starts at offset 4.
char c; // size=1, offset=8 (next available address)
}; // Total size so far is 9 bytes.
// But the largest member is 'b' with size 4.
// The total size must be a multiple of 4.
// So, we add 3 bytes of padding at the end.
// Final size = 12 bytes.
你可以用 sizeof(struct MyStruct) 来验证,结果很可能是12。
- 大小取决于类型和平台:变量的内存大小由其数据类型决定,但具体数值受编译器和目标平台(如32/64位)影响。
- 永远使用
sizeof:不要硬编码类型的大小,在编写可移植的代码时,sizeof是获取内存大小的唯一可靠方法。 - 指针大小与寻址能力相关:在64位系统上,所有指针都是8字节;在32位系统上,所有指针都是4字节。
- 内存对齐影响结构体大小:结构体的实际大小可能大于其所有成员大小之和,这是由内存对齐规则决定的,目的是为了性能。
