c
Some checks are pending
Deploy / build (push) Waiting to run
Deploy / Deploy (push) Blocked by required conditions

This commit is contained in:
许大仙 2024-10-09 09:34:19 +08:00
parent 013717e57e
commit 62dfe38dea

View File

@ -853,20 +853,80 @@ int main() {
}
```
## 2.6 #defind 定义常量 VS const 定义常量
## 2.6 `#define` 定义常量 VS `const` 定义常量
* #defind 定义常量 和 const 定义常量的对比,如下所示:
### 2.6.1 概述
| 类别 | 说明 |
| -------- | ---- |
| 执行时机 | |
| | |
| | |
* `#define``const` 都可以用来定义常量,但它们的工作方式和应用场景有所不同。
### 2.6.2 语法和定义方式
* `#define` 是一个预处理指令,用来定义宏。在编译时,所有的宏会被预处理器展开为它们定义的值,类似于文本替换。
* ① 执行时机:`#define` 是预处理指令,在编译`之前`执行;`const` 是关键字,在编译`过程`中执行。
* ② 类型检查:`#define` 定义常量`不用指定类型``不进行类型检查`,只是简单地文本替换;`const` 定义常量`需要指定数据类型``会进行类型检查`,类型安全性更强。
```c
#define PI 3.14159
```
* `const`是一个编译时常量,用来定义具有类型的常量变量。它是由编译器处理的,并且在运行时仍然可以保留类型信息。
```c
const float PI = 3.14159;
```
### 2.6.3 类型检查
* `#define`没有类型,它只是简单的文本替换,不会进行类型检查。因此,如果在宏中定义了错误的类型,可能导致编译错误或运行时错误。
```c
#define MAX 10 + 20 // 实际展开后可能是 MAX = 10 + 20而不是 30
```
* `const`具有类型,编译器会进行类型检查。如果定义时类型不匹配,会报编译错误。
```c
const int MAX = 30; // 定义时指定了类型,类型检查严格
```
### 2.6.4 作用域
* `#define`宏没有作用域的概念,它是在预处理时进行全局替换的。因此,可能会引发意外的替换问题,尤其是在复杂项目中。
```c
#define SIZE 10 // SIZE 可能在其他文件中也被不小心替换
```
* `const`具有作用域,它遵循 C 语言的作用域规则(比如局部作用域、全局作用域)。这使得 `const` 定义的常量更安全,因为它们只能在指定的范围内使用。
```c
const int SIZE = 10; // 可以局部或全局定义,不会引发冲突
```
### 2.6.5 调试
* `#define`在调试时,宏常量被替换为字面值,因此调试工具中无法看到它的原始名称,只能看到被替换后的值。
* `const`常量在编译后依然存在,因此在调试时可以直接看到常量的名称和它的值,调试体验更好。
### 2.6.6 内存分配
* `#define`宏在预处理阶段替换,不占用内存。
* `const` 常量会被分配内存,特别是在全局或静态情况下,但它也可以被优化为编译时常量,有时也不会占用额外的内存。
### 2.6.7 适用场景
* `#define`通常用于定义简单的常量值、条件编译或宏函数(用于文本替换)。适合不需要类型、安全性检查的场合。
* `const`用于定义类型安全的常量,适合需要进行类型检查或确保作用域的场合。
### 2.6.8 总结
* `const` 更加安全,尤其是在需要类型检查和局部作用域的时候;而 `#define` 常用于需要简洁的文本替换或宏定义。`const` 和 `#define` 对比的表格,如下所示:
| 特性 | `#define` | `const` |
| -------- | ------------------ | --------------------- |
| 类型检查 | 无类型检查 | 有类型检查 |
| 作用域 | 无(全局替换) | 有作用域(局部/全局) |
| 调试支持 | 差(替换为字面值) | 好(保留名称) |
| 内存开销 | 无 | 可能会有 |
| 使用场景 | 宏、条件编译 | 类型安全的常量 |