5 常量的声明与使用,#define 与 const 定义常量及二者区别

目录

1 认识常量

1.1 什么是常量

1.2 常量的分类

2 常量的定义

2.1 使用 #define 定义常量

2.1.1 介绍

2.1.2 语法格式

2.1.3 案例演示

2.1.4 执行时机

2.1.5 注意事项

2.2 使用 const 定义常量

2.2.1 介绍

2.2.2 语法格式

2.2.3 案例演示

2.2.4 执行时机

2.2.5 注意事项

3 #define 和 const 定义常量的区别

3.1 执行时机

3.2 类型检查

3.3 作用域和存储类别

3.4 调试和可读性

4 测试题


1 认识常量

1.1 什么是常量

        常量(Constant)是指在程序运行时其值不能被改变的量。这些值通常用于存储那些不会更改的数据,比如数学中的 π 值、程序中用于比较或控制的固定值等。

1.2 常量的分类

        字面量常量在程序中直接书写的常量值,不需要定义或声明就可以直接使用。这些常量包括整数常量、浮点数常量、字符常量等。

        标识符常量:通过特定的标识符来引用的常量值,使用标识符作为常量名,包括 #define 定义的标识符常量 const 关键字定义的标识符常量以及枚举常量。 


2 常量的定义

        字面量常量不需要定义或声明,我们主要学习如何定义标识符常量,习惯上常量名使用大写字母来命名,以便与变量区分。

2.1 使用 #define 定义常量

2.1.1 介绍

        #define 定义常量,叫作宏定义,就是用一个标识符来表示一个常量值,如果在后面的代码中出现了该标识符,那么在预处理阶段就会全部替换成指定的常量值,即用宏体替换所有宏名,简称宏替换

2.1.2 语法格式

#define 常量名 常量值
  • 不要以分号结尾,如果有分号,分号会成为常量值的一部分。
  • #define 必须写在 main 函数的外面(有些编译器的扩展允许 #define 写在 main 函数里,但强烈不建议这么做)。

2.1.3 案例演示

#include <stdio.h>

// 使用宏定义定义常量 PI,常量值 3.14
#define PI 3.14

int main()
{
    double area;
    // 圆的半径
    double r = 1.2;
    // 计算圆的面积
    area = PI * r * r;
    // 输出面积
    printf("圆的面积是(保留到小数点后两位) : %.2f\n", area);

    // 将圆的半径扩大二倍
    r = 2.4;
    // 计算圆的面积
    area = PI * r * r;
    // 输出面积会扩大四倍
    printf("圆的面积是(保留到小数点后两位) : %.2f\n", area);

    return 0;
}

        输出结果如下所示:

2.1.4 执行时机

        对于 #define 指令,预处理器预处理阶段会执行一个关键的文本替换过程。它遍历整个源代码,查找所有与宏定义名称相匹配的文本实例,并将这些实例直接替换为宏定义中指定的内容。这个替换过程是纯粹的文本操作,不涉及任何语法或类型的检查。因此,如果宏替换后的结果导致了语法错误或类型不匹配,这些问题只有在预处理后的代码被编译器进一步处理时才会暴露出来。

        在上面这个程序中,#define PI 3.14 这行代码定义了一个名为 PI 的宏,它的替换文本是 3.14。在预处理阶段,预处理器会查找源代码中所有的 PI,并将它们替换为 3.14。这个过程在编译之前(预处理阶段)完成,编译器看到的是已经替换好的源代码。然后,编译器会对这些代码进行编译,生成可执行文件或目标代码。

        我们可以在终端中输入预处理指令:gcc -E .\chapter04\define.c -o .\chapter04\define.i ,然后查看生成的 define.i 文件内容,会发现代码中的 PI 已经全部替换成了对应的数值 3.14,如下所示:

2.1.5 注意事项

        由于 #define 指令的宏替换只是纯粹的文本替换,所以在使用时需要注意可能发生的意外情况,比如宏展开导致的运算符优先级问题。例如:

#include <stdio.h>
 
// 纯粹的文本替换
#define PI 3+2
 
int main() {
    int i = PI * 2; // 3 + 2 * 2 = 7
    printf("i=%d\n", i); // i=7 而不是 10
    return 0;
}

        上面这个例子最终的输出结果是 i=7 而不是 i=10,原因是符号常量 PI 是直接替换的效果。PI 会被直接替换为 3+2,表达式 3 + 2 * 2 会被计算为 3 + (2 * 2),结果是 7。 

2.2 使用 const 定义常量

2.2.1 介绍

        const 关键字用于声明一个变量为常量,这意味着该变量的值在初始化之后就不能被修改。使用 const 定义常量是 C90 标准就已经引入的特性,但在后续的标准(如 C99、C11 等)中得到了进一步的加强和明确。这种方式定义常量时需要在变量的数据类型前再加上一个 const 关键字

        跟使用 #define 定义宏常量相比,const 定义的常量具有明确的数据类型,这使得它在编译时能够接受类型检查,所以会更加安全和方便,所以推荐使用 const 来定义常量。

2.2.2 语法格式

const 数据类型 常量名 = 常量值;

2.2.3 案例演示

#include <stdio.h>

// 使用 const 关键字定义常量 PI
const double PI = 3.14;

int main()
{
    double area;    // 声明变量 area 用于存储圆的面积
    double r = 1.2; // 声明并初始化变量 r 为圆的半径

    // 计算圆的面积并赋值给变量 area
    area = PI * r * r;

    // 使用 printf 函数输出圆的面积,保留两位小数
    printf("圆的面积是(保留到小数点后两位) : %.2f\n", area); 
    return 0; // 程序正常结束
}

        输出结果如下所示:

2.2.4 执行时机

        与 #define 不同,const 常量是在编译过程中处理的,而不是在预处理阶段

        我们依然通过在终端中输入预处理指令:gcc -E .\chapter04\const.c -o .\chapter04\const.i ,然后查看生成的 const.i 文件内容,会发现代码中的 PI 并没有替换成对应的数值,还是常量的形式,如下所示:

2.2.5 注意事项

        在 C 语言中,使用 const 声明的变量必须在声明时即赋予一个初始值,以确保其在程序的整个运行期间都保持固定不变。如果声明时未提供初始值,后续再对其进行赋值,编译器将报错,因为 const 常量要求有一个明确的、不可变的初始状态。


3 #define 和 const 定义常量的区别

3.1 执行时机

        #define:这是一个预处理指令,它在编译之前的预处理阶段执行。预处理器会扫描源代码,将所有 #define 指令中定义的宏(包括常量)替换为它们对应的文本。这个过程是纯粹的文本替换,不涉及任何编译或类型检查。

        const:这是一个关键字,用于在编译时定义常量。与 #define 不同,const 常量是在编译过程中处理的,并且会进行类型检查

3.2 类型检查

        #define:由于 #define 只是简单的文本替换,它不涉及类型检查。因此,如果宏定义被错误地用于不兼容的上下文(例如,将整数宏用于浮点数运算),编译器可能不会在宏替换后立即报错,而是在后续的代码检查中才发现问题。

        const:const 常量需要指定数据类型,并且会在编译时进行类型检查。这有助于防止类型不匹配的错误,并提高了代码的类型安全性。

3.3 作用域和存储类别

        #define:#define 定义的宏没有作用域的概念,它们在整个编译单元(通常是源文件)中都是可见的。此外,#define 宏也没有存储类别(如自动、静态或外部),因为它们在预处理阶段就被替换了。

        const:const 常量可以具有作用域和存储类别。它们可以定义在函数内部(具有自动存储期),也可以定义在全局作用域中(具有静态或外部存储期,取决于是否使用了 static 关键字)。这允许更精细的控制常量的可见性和生命周期。

3.4 调试和可读性

        #define:由于 #define 宏只是文本替换,它们在调试时可能会隐藏一些重要的信息。例如,如果宏被错误地替换,调试器可能无法显示原始宏名称,而是显示替换后的文本。

        const:const 常量在调试时更容易识别和理解,因为它们保留了类型信息和作用域信息。此外,const 常量还可以被调试器直接显示其名称和值。


4 测试题

1. 请写出以下代码的运行结果:

#include <stdio.h>
const int PI = 300;

int main()
{
    PI = 250;
    printf("%d", PI);
}

【答案】报错

【解析】常量的值不能修改!

### 回答1: const常量和#define区别在于: 1. const常量是在编译时分配内存,而#define是在预处理时进行文本替换,不会分配内存。 2. const常量类型,可以进行类型检查,而#define没有类型,只是简单的文本替换。 3. const常量可以进行地址取操作,而#define不可以。 4. const常量可以在多个文件中共享,而#define只能在定义它的文件中使用。 5. const常量可以进行调试,而#define不可以。 因此,建议在定义常量时优先使用const,而不是#define。 ### 回答2: const常量是C++中常用的一种数据类型定义const常量之后,它的不能改变,因此const常量也被称为“只读变量”。 定义const常量的语法格式如下: const 数据类型 常量名 = 常量; 其中,const表示定义一个常量,数据类型指定了常量类型常量名指定了常量的名字,常量则指定了常量。 与const常量类似的是#define定义,它们的区别在于前者是编译器处理的常量,后者是预处理器处理的常量。宏定义不会对常量进行类型检查,容易出现错误,在C++中往往使用const常量来代替宏定义const常量非常有用,它可以保证程序在运行过程中某些数不被无意中修改。另外,const常量也可以作为参数传递给函数,这样可以避免函数中修改传入参数的,增强程序的可读性和健壮性。在类中,const常量也可以用来声明成员变量,表示它的在对象生命周期内不会改变。 总之,const常量是C++中非常重要的一种数据类型,它可以保证程序的安全性和稳定性,非常适合用于需要保证某些不被随意修改的场合。 ### 回答3: let变量在JavaScript中的区别是什么? 在JavaScript中,const常量和let变量是两种常用的声明变量的方式。它们与var的不同之处在于它们在声明后具有不同的作用域和可变性。具体区别如下: 1. const常量声明一个常量时,必须立即初始化常量,不能再次赋。而且,const声明常量是块级作用域,在声明的块级别内可见。此外,如果尝试重新分配const常量,将会引发TypeError错误。 2. let变量:初始化后,let声明的变量可以更改其。与const一样,let变量也是在块级别的作用域中声明的,但是它在作用域中声明的变量可以被更改赋。 总的来说,const常量和let变量在声明后都可以使用块级作用域,这意味着它们在声明块级别内可见,而不是在函数级别内。但是,const常量以初始化之后不能进行赋,同时,let变量可以被重新赋。选择const还是let变量,需要根据实际需求和定义变量的用途来判断。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Thanks_ks

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值