C语言 const 和 define 区别

零基础 C/C++ 学习路线推荐 : C/C++ 学习目录 >> C 语言基础入门


一.const 使用

const 是 constant 的缩写,“恒定不变”的意思。被 const 修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。所以很多 C++ 程序设计书籍建议:“Use const whenever you need”。


1.const修饰变量

/******************************************************************************************/
//@Author:猿说编程
//@Blog(个人博客地址): www.codersrc.com
//@File:C语言 const 和 define 区别
//@Time:2021/07/04 08:00
//@Motto:不积跬步无以至千里,不积小流无以成江海,程序人生的精彩需要坚持不懈地积累!
/******************************************************************************************/

#include <stdio.h>

int main() {
    const int a = 20 ;
    printf("a = %d\n",a);
    a = 200 ;
    printf("a = %d\n",a);
    return 0;
}

/*
 输出:
 
 Compilation Failed
 error: assignment of read-only variable 'a'
     6 |     a = 200 ;
       |     ~~^~~~~
 */

用 const 定义的变量的值是不允许改变的,即不允许给它重新赋值,即使是赋相同的值也不可以。并且 const 修饰的变量在定义的时候就给它赋初值,否则报错:

error: uninitialized 'const ' [-fpermissive]

详细解释可以直接跳转:const 修饰变量


2.const修饰指针


//以下两者等价,表示 *p 不可变。*p 表示的是指针变量 p 所指向的内存单元里面的内容,此时这个内容不可变;
const int *p
int const *p


//此时 const 修饰的是 p,所以 p 中存放的内存单元的地址不可变,而内存单元中的内容可变。即 p 的指向不可变,p 所指向的内存单元的内容可变;
int * const p


//*p 和 p 都被修饰了,那么 p 中存放的内存单元的地址和内存单元中的内容都不可变;
const int * const p

详细解释可以直接跳转:const修饰指针


3.const修饰在函数名前面

当 const 在函数名前面的时候修饰的是函数返回值;在函数名后面表示是 C++ 常成员函数,该函数不能修改对象内的任何成员,只能发生读操作,不能发生写操作。

const char * GetString(void);
const int    GetInt(void);
const float  GetFloat(void);
const double GetDdouble(void);

如果给以“指针传递”方式的函数返回值加 const 修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加 const 修饰的同类型指针;

const char * GetString(void);

//如下语句将出现编译错误:
//char *str = GetString();

//正确的用法是
const char  *str = GetString();

如果函数返回值采用“值传递方式”,由于函数会把返回值复制到外部临时的存储单元中,加 const 修饰没有任何价值。

int GetInt(void);

const int GetInt(void);

以上两个函数都是都是独立存在的,并非同一个函数;


4.const修饰在函数名后面

当 const 在函数名前面的时候修饰的是函数返回值;在函数名后面表示是 C++ 常成员函数,该函数不能修改对象内的任何成员,只能发生读操作,不能发生写操作。

/******************************************************************************************/
//@Author:猿说编程
//@Blog(个人博客地址): www.codersrc.com
//@File:C语言 const 和 define 区别
//@Time:2021/07/04 08:00
//@Motto:不积跬步无以至千里,不积小流无以成江海,程序人生的精彩需要坚持不懈地积累!
/******************************************************************************************/


class People
{
 public:
    int talk(void);
    int eat(void) const; // const 成员函数
 private:
    int m_age;
   
};
int People::eat(void) const
{
    ++m_age; // 编译错误,企图修改数据成员m_num
    talk();  // 编译错误,企图调用非const函数
    return    m_age;
}
  • const 对象只能访问const 成员函数,而非 const 对象可以访问任意的成员函数,包括const 成员函数;
  • const 对象的成员是不可修改的,然而 const 对象通过指针维护的对象却是可以修改的;
  • const 成员函数不可以修改对象的数据,不管对象是否具有 const 性质.它在编译时,以是否修改成员数据为依据,进行检查;
  • 然而加上 mutable 修饰符的数据成员,对于任何情况下通过任何手段都可修改,自然此时的 const 成员函数是可以修改它的;

5.const修饰函数参数

如果函数参数采用“指针传递”,那么加 const 修饰可以防止意外地改动该指针,起到保护作用。

void StringCopy (char*strDestination, const char *strSource);

其中 strSource 是输入参数,strDestination 是输出参数。给 strSource 加上 const 修饰后,如果函数体内的语句试图改动 strSource 的内容,编译器将指出错误。

如果输入参数采用“值传递”,由于函数将自动产生临时变量用于复制该参数,该输入参数本来就无需保护,所以不要加 const 修饰。

例如不要将函数 void Func1(int x) 写成 void Func1(const int x)。

如果参数作为输出参数,不论它是什么数据类型,也不论它采用“指针传递”还是“引用传递”,都不能加 const 修饰,否则该参数将失去输出功能(因为有 const 修饰之后,不能改变他的值)。

如果参数作为输入参数,可以防止数据被改变,起到保护作用,增加程序的健壮性;


二.define 使用


1.define定义常量

C 语言中,可以用 #define 定义一个标识符来表示一个常量,用 #define 定义标识符的一般形式为:

#define  标识符  常量   //注意define最后没有分号
//例如:
#define MAX_VALUE 100       //定义整型变量MAX_VALUE值为100
#define USER_NAME "huge"    //定义字符串变量USER_NAME值为"huge"
#define PI 3.1415926        //定义浮点数变量PI值为3.1415926

凡是以 # 开头的均为预处理指令,预处理又叫预编译。预编译不是编译,而是编译前的处理。这个操作是在正式编译之前由系统自动完成的。


2.define定义函数

//定义常量
#define MAX_VALUE 100       //定义整型变量MAX_VALUE值为100
#define USER_NAME "huge"    //定义字符串变量USER_NAME值为"huge"
#define PI 3.1415926        //定义浮点数变量PI值为3.1415926

//定义函数
#define MAX(a,b) (a>b)?a:b  //取两个数最大值
#define MIN(a,b) (a<b)?a:b  //取两个数最小值

3.define定义多行函数

//定义常量
#define MAX_VALUE 100       //定义整型变量MAX_VALUE值为100
#define USER_NAME "huge"    //定义字符串变量USER_NAME值为"huge"
#define PI 3.1415926        //定义浮点数变量PI值为3.1415926

//定义简单函数
#define MAX(a,b) (a>b)?a:b  //取两个数最大值
#define MIN(a,b) (a<b)?a:b  //取两个数最小值

//定义复杂多行的函数
#define   MACRO(arg1,   arg2)   do   {   \ 
   \ 
stmt1;   \ 
stmt2;   \ 
   \ 
}   while(0)  
  
//关键是要在每一个换行的时候加上一个 "\ "

使用define定义一个多行的复杂函数,关键是要在每一个换行的时候加上一个 \


4.define防止头文件重复包含

通过 #ifndef / #define 解决头文件重复包含

#ifndef __XXX_H__
#define __XXX_H__

int a=1;

#endif

上面的伪代码如下:

如果(没有定义宏__XXX_H__)
{
    那么直接定义宏__XXX_H__
    定义变量a 并且赋值为 1
}
结束程序
  • 假如第一次包含时,由于没有定义宏 __XXX_H__,所以做了两件事,定义宏 __XXX_H__,然后定义 int a = 1;
  • 假如第二次包含时,由于已经定义宏 __XXX_H__,所以啥都不做;
  • 假如第N次包含时,由于已经定义宏 __XXX_H__,所以啥都不做;
  • 整个过程,无论头文件被包含多少次,变量 a 只被定义一次,不会有重复包含重复定义的问题存在!

三.const 和 define 区别


1.就起作用的阶段而言

#define 是在编译的预处理阶段起作用,而 const 是在 编译、运行的时候起作用。


2.就起作用的方式而言

#define 只是简单的字符串替换,没有类型检查。而 const 有对应的数据类型,是要进行判断的,可以避免一些低级的错误。


3.就存储方式而言

#define 只是进行展开,有多少地方使用,就替换多少次,它定义的宏常量在内存中有若干个备份; const 定义的只读变量在程序运行过程中只有一份备份。


4.从代码调试的方便程度而言

const 常量可以进行调试的,define 是不能进行调试的,因为在预编译阶段就已经替换掉了。


5.从效率程度而言

编译器通常不为普通 const 常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高


四.const 优点

  • 1.const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。
  • 2.有些集成化的调试工具可以对 const 常量进行调试,但是不能对宏常量进行调试。
  • 3.const 可节省空间,避免不必要的内存分配,提高效率

五.猜你喜欢

  1. C语言 数组下标越界和内存溢出区别
  2. C语言 指针声明和定义
  3. C语言 指针 p++ / p–
  4. C语言 p++/(p)++/(p++)/p++
  5. C语言 使用指针遍历数组
  6. C语言 指针和数组区别
  7. C语言 指针数组和数组指针区别
  8. C语言 空指针 NULL
  9. C语言 void 指针
  10. C语言 野指针
  11. C语言 函数值传递和址传递
  12. C语言 函数缺省参数
  13. C语言 函数不定长参数
  14. C语言 函数指针
  15. C语言 指针函数
  16. C语言 回调函数 callback
  17. C语言 typedef
  18. C语言 define 定义常量
  19. C语言 define 防止头文件重复包含
  20. C语言 #pragma once
  21. C语言 #include <> 与 #include “” 区别
  22. C语言 const 修饰变量
  23. C语言 const 修饰指针
  24. C语言 const 修饰函数
  25. C语言 const 修饰函数参数
  26. C语言 const 和 define 区别

未经允许不得转载:猿说编程 » C语言 const 和 define 区别
喜欢(3) 打赏

评论抢沙发

评论前必须登录!

不积跬步无以至千里,不积小流无以成江海,程序人生的精彩需要坚持不懈地积累!!

开始学习

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏