C++ 常量与 const —— #define vs const 全面对比详解

目录

一、前言

二、定义常量的两种方式

1️⃣ 使用 #define 预处理器宏

2️⃣ 使用 const 关键字

三、#define vs const 对比表 

四、边界效应实例 

五、const 常量的规则与陷阱

1️⃣ 必须初始化

2️⃣ 外部 const 可使用 extern

3️⃣ const 在指针中的多种修饰方式

(1) 指向常量的指针(底层 const)

(2) 常量指针(顶层 const)

(3) 同时为常量指针且指向常量

4️⃣ const 修饰引用

六、数据范围与类型注意 

七、宏定义小陷阱:分号错误 

八、const 的扩展应用 

九、完整实战例子:计算圆面积与周长

十、总结归纳

十一、建议的命名规范

十二、总结


一、前言

在 C++ 编程中,常量(Constant) 是极其重要的基础概念。
从早期的 #define 宏定义到现代的 const 关键字,它们都能实现“值不变”的目的,但背后的机制完全不同。

本文章从 定义方式 → 底层原理 → 指针修饰 → 实例分析 → 对比总结
带你系统掌握 #defineconst 的所有知识点。


二、定义常量的两种方式

1️⃣ 使用 #define 预处理器宏

#include <iostream>
using namespace std;

#define LENGTH 10
#define WIDTH 5
#define NEWLINE '\n'

int main() {
    int area = LENGTH * WIDTH;
    cout << area << NEWLINE;
    return 0;
}

输出:

50

📌 特点

  • 宏是预处理阶段进行的简单文本替换

  • 没有类型检查

  • 编译器看不到它(调试困难);

  • 不能使用作用域、命名空间、函数参数等


2️⃣ 使用 const 关键字

#include <iostream>
using namespace std;

int main() {
    const int LENGTH = 10;
    const int WIDTH = 5;
    const char NEWLINE = '\n';

    int area = LENGTH * WIDTH;
    cout << area << NEWLINE;
    return 0;
}

输出:

50

📌 特点

  • const 是一种 类型安全的常量声明

  • 参与编译器的类型检查;

  • 有明确的内存存储位置;

  • 可与函数参数、类成员、指针等结合使用。


三、#define vs const 对比表 

对比项#define 宏定义const 常量
作用阶段预处理阶段(编译前)编译阶段
类型检查无类型(字符替换)有类型(编译器检查)
存储方式不分配内存,仅替换文本分配内存,存储在数据段
调试支持无法调试(已展开)可调试,有符号信息
作用域全局有效(除非 #undef受作用域限制(块/函数/全局)
能否取消定义可用 #undef 取消不可取消
能否传递给函数❌ 不能作为参数✅ 可作为函数参数
能否指定类型❌ 不行✅ 明确的类型约束
命名规范通常大写宏名:#define PI 3.14可小写/驼峰:const double Pi = 3.14;
安全性可能有边界效应类型安全

四、边界效应实例 

#define N 2+3
int main() {
    double a = N / 2;  // 实际展开为 2+3/2 → 3.5,而非 2.5
    cout << a << endl;
}

✅ 解决方法:使用括号

#define N (2+3)

五、const 常量的规则与陷阱

1️⃣ 必须初始化

const double pi; // ❌ 错误:未初始化 
pi = 3.14159; // 不允许赋值

✅ 正确写法:

const double pi = 3.14159;

2️⃣ 外部 const 可使用 extern

// file1.cpp
extern const int MAX_VALUE;

// file2.cpp
const int MAX_VALUE = 100;

3️⃣ const 在指针中的多种修饰方式

        这里可以看我之前写过的文章,里面有详细的记载 const 和 指针 的应用(内容常量,常量指针...),阅读完这三篇内容 读者即可完全掌握const与指针相关操作:C++ 指针与引用全面解析:const 修饰三种形式 + 底层机制 + 八股总结-CSDN博客https://blog.csdn.net/m0_58954356/article/details/154637648?spm=1001.2014.3001.5502C++ 变量作用域 & 存储期 & 链接性:const / static / extern 全面解析-CSDN博客https://blog.csdn.net/m0_58954356/article/details/154607017?spm=1001.2014.3001.5502

(1) 指向常量的指针(底层 const)
const int *p = &a;
*p = 10;  // ❌ 不允许修改指向内容
p = &b;   // ✅ 可以修改指向
(2) 常量指针(顶层 const)
int *const p = &a;
*p = 10;  // ✅ 内容可改
p = &b;   // ❌ 指针本身不能改
(3) 同时为常量指针且指向常量
const int *const p = &a;
*p = 10;  // ❌ 不可改内容
p = &b;   // ❌ 不可改指向

🧩 口诀记忆法

  • const* 左:内容不可改(底层 const)

  • const* 右:指针不可改(顶层 const)

  • 两边都有:都不可改


4️⃣ const 修饰引用

int a = 10;
const int &ref = a;
ref = 20;  // ❌ 不允许修改
a = 20;    // ✅ 仍可通过变量改

引用本身不是变量,没有顶层 const,只有底层 const。


六、数据范围与类型注意 

const int maxn = 1e+10;  // 超过 int 范围,溢出

✅ 改为:

const long long maxn = 1e+10;

或者:

#define MAXN 1e+10 // 无类型,浮点常量替换

注意 %d / %lld 输出格式要匹配类型!


七、宏定义小陷阱:分号错误 

#define age2 12;
#define age3 10;
int dd = age2 + age3;
cout << dd; // 输出 12 而不是 22!

原因:宏替换后变成 12;+ 10; ,语句提前结束。
✅ 正确写法:

#define age2 12 
#define age3 10

八、const 的扩展应用 

场景示例含义
修饰变量const int a = 10;只读变量
修饰指针const int *p指向常量的指针
修饰函数参数void func(const string &name);防止修改参数
修饰成员函数void show() const;不修改类成员
修饰返回值const string getName();返回只读对象

九、完整实战例子:计算圆面积与周长

#include <iostream>
using namespace std;

#define PI1 3.14              // 宏定义
const double PI2 = 3.1415926; // 常量定义

int main() {
    double r = 10;
    cout << "Using #define: area=" << PI1*r*r
         << ", perimeter=" << 2*PI1*r << endl;

    cout << "Using const:   area=" << PI2*r*r
         << ", perimeter=" << 2*PI2*r << endl;
}

输出:

Using #define: area=314, perimeter=62.8
Using const:   area=314.159, perimeter=62.8319

十、总结归纳

项目#defineconst
类型无类型有类型
安全性不安全类型检查
调试不可调试可调试
作用域全局局部/全局
生命周期编译前替换运行期存在
存储位置代码段数据段
取消定义可用 #undef不可取消
使用场景条件编译、宏函数常量、参数、成员保护

十一、建议的命名规范

类型命名示例说明
宏常量#define MAX_SPEED 120全大写+下划线
const 常量const double Pi = 3.14159;首字母大写或驼峰命名

十二、总结

#define早期 C 语言的产物
const 则是 C++ 引入的类型安全改进版

在现代 C++ 开发中,建议:

  • 尽量使用 const 替代 #define

  • 只有在需要条件编译或跨平台时才用 #define

  • 合理利用 const 修饰函数、指针、引用,让代码更安全、可读、可维护。

源码直接下载地址: https://pan.quark.cn/s/d280357b18e5 在网页构建领域中,HTML5被视为当代网页工程的基础规范,其问世显著增强了页面的视觉表现力用户互动性。本工程致力于运用HTML5技术开发一个电视剧信息展示页面,目的是呈现诸如剧名、演员构成、故事梗概等电视剧关键资料。接下来将深入阐释如何借助HTML5的结构化组件和样式管理功能达成此项目目标。 我们必须掌握HTML5的核心框架。一个规范的HTML5文档一般包含`<!DOCTYPE html>`声明、`<html>`根标记、`<head>`头部标记和`<body>`主体标记。在头部区域,可以配置网页的基本元数据,例如字符集设定、页面标题等。在主体部分,将具体构建电视剧信息列表的内容。 电视剧展示页面通常包含多个条目,每个条目对应一部电视剧。HTML5中的`<section>`标记用于内容模块化,适合表示单个电视剧的详细信息区域。每个`<section>`内部,可使用`<h2>`标题标记显示剧名,`<img>`图像标记插入宣传剧照,`<p>`段落标记呈现剧情介绍,而`<ul>`无序列表`<li>`列表项标记则用于罗列演员阵容。 为了优化页面布局,需要借助CSS(层叠样式表)进行样式管理。HTML5引入了创新的CSS选择器布局模型,例如Flexbox和Grid,使页面布局更加灵活多变。在此场景下,可以利用Flexbox为电视剧信息列表实现自适应布局,保障在不同设备尺寸下均能呈现理想视觉效果。具体操作时,可将`<section>`标记设定为Flex容器,通过`display: flex;`属性,并运用`justify-content`和`align-items`属性调整子元素的对...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值