本文最后更新于53 天前,其中的信息可能已经过时,如有错误请发送邮件到3206482802@qq.com
我们先来看一段简单的C语言代码,它声明了多种不同类型的变量:
#include <stdio.h>
int main()
{
int a;
short b;
long c;
float d;
double e;
char f;
signed g;
unsigned h;
return 0;
}
下面逐行解释这些变量声明的含义,并顺势引入必要的概念。
1. 整型变量 int a;
- 含义:定义了一个整型变量
a。语句以分号;结束。 - 存储规则:
a只能存储整数。如果用浮点数初始化,会直接截断小数部分(向零取整)。int a = 2.2222;→a的值为2int a = 2.5555;→a的值为2(小数部分被丢弃,不会四舍五入)int a = -3.8;→a的值为-3
- 大小:通常占用 4 字节(32 位),具体取决于编译器和平台。
- 此处出现的
2.2222等就是字面常量,后文会详细介绍。
2. 短整型 short b;
- 定义了一个短整型变量
b。 - 同样只能存储整数,浮点数赋值时截断规则与
int相同。 - 通常占用 2 字节(16 位)。
3. 长整型 long c;
- 定义了一个长整型变量
c。 - 赋值规则与
int一致,只能保存整数。 - 通常占用 4 字节(Windows 等环境)或 8 字节(Linux 64 位),遵循
sizeof(long) >= sizeof(int)。
4. 单精度浮点型 float d;
- 定义了一个单精度浮点型变量
d。 d可以存储实数(小数),但由于计算机内部二进制表示的限制,部分数值会存在微小的精度误差。- 例:
float d = 2.2222;实际存储的值可能接近2.2221999,这是正常现象。
- 例:
- 通常占用 4 字节(32 位)。
5. 双精度浮点型 double e;
- 定义了一个双精度浮点型变量
e。 - 也能存储实数,精度比
float更高,但依然可能有轻微误差。 - 通常占用 8 字节(64 位)。
6. 字符型 char f;
- 定义了一个字符型变量
f。 f可以存储一个字符(如字母、数字、标点),底层实际存放的是该字符对应的整数编码(通常为 ASCII 码)。- 例:
char f = 'a';→f中存储的值是97(字符'a'的 ASCII 码)。
- 例:
- 大小:占用 1 字节(8 位)。
这里必须展开讲一下字符和字符串:
- 字符常量:用单引号括起来,如
'a'、'1'、'?'。在C语言中,字符常量的类型是int,其值就是对应的编码值。例如'a'就是97。 - 转义字符:一些特殊字符用反斜杠开头表示,也是字符常量。
'\n'换行,'\t'制表符,'\\'反斜杠本身,'\''单引号。
- 字符串常量:用双引号括起来,如
"hello"。它与字符常量完全不同:字符串在内存中是一串字符,并且末尾自动添加一个空字符'\0'作为结束标志。因此'a'和"a"是两种东西,前者是一个整数,后者是一个字符数组。
7. 有符号整型 signed g;
- 定义了一个有符号整型变量
g,等价于signed int,也就是普通的int。 - 可以存储正整数、负整数和零。
- 占用空间通常与
int相同,为 4 字节。
8. 无符号整型 unsigned h;
- 定义了一个无符号整型变量
h,等价于unsigned int。 h只能存储非负整数(0 和正数)。- 特别注意:如果把一个负数赋值给无符号变量,不会简单地“消除负号”,而是发生隐式转换,结果是一个很大的正数(由补码转换规则决定)。
- 例(32位系统):
unsigned h = -6;→h的值是4294967290(即 2³² – 6),而不是6。
- 例(32位系统):
- 占用空间通常与
int相同,为 4 字节。
补充1:常量的概念
在变量解释中反复出现的 2.2222、'a'、-6 等都是常量。常量指程序运行期间其值不能改变的量。C语言中主要有以下形式:
- 字面常量:直接写出来的值。
- 整型常量:
100、-5 - 浮点常量:
3.14、2.5f(f后缀表示float型) - 字符常量:
'A'、'\n' - 字符串常量:
"Hello"
- 整型常量:
- const 修饰的只读变量:cconst int MAX = 100;这样定义的
MAX本质上仍是变量,但被限定为只读,初始化后不能再修改。它与字面常量的区别在于它有地址、有类型,可以在编译期或运行期确定值。 - 符号常量(宏定义):c#define PI 3.14159这是预处理指令,在编译前会把代码中所有
PI替换为3.14159。宏不是变量,没有类型,不分配内存,只是文本替换。
理解常量有助于明白 int a = 2.2222; 中 2.2222 是浮点字面常量,而 a 是变量。
补充2:变量初始化的逻辑
声明变量只是向编译器“预订”了一块内存,而这块内存里原来是什么值,取决于初始化。这是新手最容易出错的地方。
1. 定义时初始化 vs 先定义后赋值
int a = 10; // 初始化:创建变量时同时赋予初值 int b; // 未初始化 b = 10; // 赋值:为已存在的变量赋予新值
对于局部变量(在函数内部声明的,如 main 函数里的 a),定义时如果不初始化,它的值是不确定的(垃圾值),直接读取会导致未定义行为。所以强烈建议永远在定义变量的同时进行初始化。
2. 不同类型初始化时的隐式转换
- 浮点数 → 整数:截断小数部分(如
int a = 3.9;得3)。 - 整数 → 浮点数:提升精度,如
float f = 5;实际存储5.0。 - 负数 → 无符号数:转换为补码对应的无符号值,得到一个很大的正数(前面
unsigned h = -6的例子)。 - 大范围类型 → 小范围类型:可能发生截断或符号丢失(需谨慎)。
3. 正确的初始化习惯
int count = 0; double price = 0.0; char ch = '\0'; // 空字符
即使还没有确切的值,也应先赋予一个安全的默认值,避免垃圾值导致的随机错误。
总结:常用类型大小一览
| 类型 | 常见字节数 | 值域简要说明 |
|---|---|---|
char | 1 | -128 ~ 127 或 0 ~ 255 |
short | 2 | -32,768 ~ 32,767 |
int | 4 | 约 -21亿 ~ 21亿 |
long | 4 或 8 | 至少与 int 范围一样大 |
float | 4 | 约 6~7 位有效数字 |
double | 8 | 约 15~16 位有效数字 |
unsigned int | 4 | 0 ~ 约 42亿 |
注意:确切大小可通过 sizeof 运算符在当前环境中查看。例如:
printf("int: %d bytes\n", sizeof(int));
printf("double: %d bytes\n", sizeof(double));
这样可以让你在自己的编译器上验证上面表格里的数值。
这样,我们就完整地走过了 变量声明、数据类型、常量、初始化逻辑 的基础闭环。掌握这些,后续的表达式计算、数组、指针等知识就有了牢固的根基。