C笔记20250325
一:宏常量 和 const常量的区别
宏常量
- 使用预处理器指令
#define
来定义。
#define PI 3.14159
- 没有类型信息,仅仅是简单的文本替换。这意味着编译器不会对宏进行类型检查,可能导致潜在的错误。
- 宏不是变量,不占用内存空间。它只是在预处理阶段将所有出现的宏名替换为相应的值。
-
由于宏仅是文本替换,在调试时查看变量值时无法直接看到宏的名字,这可能使调试更加困难。
-
宏的作用范围从定义点开始直到文件结束或遇到
#undef
指令为止,不具备块级作用域的概念。宏是全局性的,除非特别限制在一个文件内通过条件编译实现。 -
适合用于定义简单的常数值,特别是当这个值需要被用作数组大小、case标签或其他不允许有变量的地方。也常用于条件编译。
const
常量:
- 使用
const
关键字定义,并指定类型。
const double pi = 3.14159;
- 具有明确的数据类型,编译器可以执行类型检查,有助于减少编程错误。
- 通常会在内存中分配空间,
-
可以在调试器中查看const常量的名称和值,提供更好的调试支持。
-
遵循C语言的作用域规则,可以根据定义位置有不同的作用域(如局部、文件作用域等)。可以通过
static
关键字限制其作用域到单个文件。 -
适用于需要类型安全的场合,以及希望利用C语言作用域规则控制可见性的场景。
二: #define MAX 10 与const int b = 10的区别
#define MAX 10
- 这是通过预处理器(Preprocessor)实现的宏定义。
- 在编译之前,所有的
MAX
都会被直接替换为10
。 - 它是一个简单的文本替换机制,不涉及类型检查。
- 没有类型信息,只是简单的文本替换。
- 宏定义的作用范围从定义处开始,直到文件结束,或者遇到
#undef
指令。 - 它没有块作用域的概念,适用于整个文件或多个文件(如果在头文件中定义并包含)。
- 不分配内存,因为它是预处理阶段的文本替换。
MAX
只是一个占位符,在编译后的代码中不存在实际的存储空间。- 因为宏定义在预处理阶段被替换,调试时无法看到
MAX
的存在。 - 如果出现错误,调试器只会显示替换后的值(如
10
),而不是MAX
。 - 因为是简单的文本替换,不会引入额外的运行时开销。
- 但在某些情况下,宏定义可能会导致代码膨胀。例如:
#define SQUARE(x) ((x) * (x))
int y = SQUARE(5 + 2); // 替换后变为 ((5 + 2) * (5 + 2)),可能会有多余的计算
- 适合用于简单的常量定义,尤其是需要跨文件共享的常量。
- 适合用于条件编译(如
#ifdef
、#ifndef
等)。
#define DEBUG_MODE 100
#ifdef DEBUG_MODE
printf("Debugging...\n");
#endif
- 如果你在代码中不小心误用了
MAX
,编译器可能不会报错。例如:
#define MAX 10
int arr[MAX]; // 正确
int x = MAX + "string"; // 错误,但编译器可能不会立即报错
const int b = 10;
- 这是一个真正的变量声明,带有类型信息(int)。
- 编译器会为 b 分配内存,并且它的值在程序运行期间不能被修改。
- 它是C语言中的常量变量,具有类型安全性。
- 具有明确的类型(int),编译器会对类型进行检查。
- 常量变量的作用范围遵循C语言的变量作用域规则。
- 如果定义在函数内部,则只在该函数内有效;如果定义在全局范围内,则在整个文件或模块内有效。
- 在内存中会分配存储空间(通常是只读区域)。
- 虽然 b 的值不能被修改,但它仍然占用一定的内存。
- 调试时可以看到 b 的名字和值,便于排查问题。
- 因为是变量,访问时可能会有微小的运行时开销(通常可以忽略)。
- 如果你试图将 b 用于不兼容的类型操作,编译器会报错。例如:
const int b = 10;
int arr[b]; // 正确
int x = b + "string"; // 编译器会报错
- 更适合用作局部常量或需要类型安全的场景。
void func() {const int size = 10;int arr[size];
}
特性 | #define MAX 10 | const int b = 10; |
---|---|---|
本质 | 预处理器宏定义 | 带类型的常量变量 |
类型检查 | 无 | 有 |
作用范围 | 文件范围(或 #undef 结束) | 遵循变量作用域规则 |
内存分配 | 无 | 有 |
调试支持 | 无 | 有 |
性能 | 无运行时开销 | 微小运行时开销(可忽略) |
适用场景 | 跨文件共享常量、条件编译 | 局部常量、类型安全要求高的场景 |