打印
[技术问答]

C和C++中const的用法比较

[复制链接]
196|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
cr315|  楼主 | 2023-3-23 10:10 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在C语言中,通常使用#define来定义常数,其后在使用该常数的地方利用定义的宏名来进行常数替换,这样可以避免在程序中到处出现magic numbers的乱象,并且#define是宏定义,不需要为其分配存储空间。但是#define是在预处理器的控制范畴内,只能简单地进行文本替换,不能进行类型安全检查,并且其作用域从#define定义点开始,直到该编译单元结束,无法进行较好的控制。

在C语言中,如果想让编译器进行constant folding,即在编译时,通过计算将复杂的常数表达式化简为一个值,通常只能用#define来进行(C99标准之前)。编译器将始终为const变量分配存储空间。const仅仅意味着定义的变量是只读的,其值不能被修改。C编译器不能将const作为一个编译时的常数来使用,而总是为其分配存储空间。因此如下定义全局数组

const int bufsize = 100;

char buf[bufsize];

尽管看起来符合我们的思维习惯,但编译将出现错误。因为bufsize占有存储空间,C编译器在编译期间不能确定它的值。

因此在C语言中,const并不是非常有用的。如果你想在一个常数表达式中使用一个符号名(也就是说必须在编译时确定其值的话),C几乎限定你只能使用预处理器的#define来进行。

在C中const是外连接的,不能将其定义放在头文件中。如果用const int bufsize;的话,可以表示一个声明(bufsize在别处定义,跟使用extern const int bufsize;是等价的),也可以表示一个定义(如果在连接时,其它地方都没有定义的话,将其初始化为0)。

针对C中const的上述局限性,C++作出了重大的改进。在C++中,可以使用const来定义常数,因为const在编译器的控制范畴内,而非由预处理器控制,所以可以进行类型安全检查,也方便进行作用域控制。

在C++中可以利用const来消除#define定义常数的方式,以提高安全性。通常C++编译器并不为const分配存储空间,而是将其定义保存在符号表中,当使用时进行简单的常数替换(像#define一样不占空间,但拥有类型安全检查和作用域控制)。因此上述不能编译通过的C代码,在C++中可以顺利地通过。当不需要分配空间时(这依赖于数据类型的复杂度和编译器的智能化程度),在类型安全检查之后,像#define一样,为了更高的效率,值将会被折叠进代码中。

因此在C++中,当使用const时并不一定意味着会分配存储空间,是否会分配空间要看是怎么使用的。通常编译器会尽力避免为其分配空间,以通过constant folding来提高效率。常见的C++将会为const变量分配存储空间的情况是:当取了某个const变量的地址时。注意通过引用来进行函数参数传递也是会取变量地址的,尽管从语法上看这并没有取地址,但是应该清楚引用在底层实现上也是通过传递地址的方式来进行的。当不得不为const变量分配空间时,C++仍然能通过一定的手段来尽量进行constant folding。如下代码所示:

const int i = 100; //典型的常数

const int j = i + 10; //从常数表达式得到值

long address = (long)&j; //因为取地址,强迫编译器为j分配存储空间

char buf[j+10]; //j+10仍然是一个常数表达式

当不得不为const分配空间时(与#define相对的别一种用法),const代表该空间在其后是只读的,所以在定义时必须初始化,因为之后已经无法进行赋值以改变其内容。

在聚合数据类型上使用const也是可以的,但是编程者必须明白编译器很可能并没有智能到能将聚合类型保存在符号表中并进行constant folding的程度,所以需要为其分配存储空间。这种情况下const的意义只是告诉编译器,这是一小片不能被改变值的存储区域。因此编译器在编译时不能确保其常量性

const int i[] = { 1, 2 ,3 ,4 };

//float f[i[3]]; //非法

struct S { int i, j; };

const S s[] = { { 1, 2 },{ 3, 4 } };

//double d[s[1].j]; //非法

使用特权

评论回复
沙发
cr315|  楼主 | 2023-3-23 10:10 | 只看该作者
以上两行非法代码都是因为在定义数组长度时,必须在编译时确定常数值,但是因为对复杂的const对象会分配存储空间,所以编译时不能完全确定其值。

在C++中,在函数外定义的const是文件作用域的,所以可以将const的定义放在头文件中。也就是说const在C++中是内连接的,不会在多个编译单元之间发生冲突。如果想声明在别的地方定义过的const变量,必须明确地用extern const int bufsize;(这是声明)。而在定义处必须显示地指定为外连接,extern const int bufsize=100;(注意这是定义,而非声明,所以要初始化,这是区别于声明的标志)

综上所述,作为一条实践准则,如果你确定某个值在其生命周期内你不会修改它,即对你而言是只读性质的话,你就应该使用const来加以修饰。这不但能避免其无意中被修改,也能使编译器通过不为其分配存储空间、减少读内存的次数等手段来产生更有效率的代码。

从本文可以看出,C和C++中const的用法和含义有许多细微的不同之处。const在指针、函数参数、返回值、类对象、成员函数等地方都有应用,在这些情况下它们都有着不能被改变之意,但运用细节又各有其特点。

使用特权

评论回复
板凳
七毛钱| | 2023-3-23 15:14 | 只看该作者
到底是学c好还是c++好

使用特权

评论回复
地板
星辰大海不退缩| | 2023-3-27 17:50 | 只看该作者
在C++中可以利用const来消除#define定义常数的方式,以提高安全性

使用特权

评论回复
5
AdaMaYun| | 2023-3-27 18:00 | 只看该作者
C是C++的基础,C++语言和C语言在很多方面是兼容的

使用特权

评论回复
6
豌豆爹| | 2023-3-28 09:18 | 只看该作者
C++还是要难点吧

使用特权

评论回复
7
小夏天的大西瓜| | 2023-3-28 13:33 | 只看该作者
C++ 进一步扩充和完善了 C 语言

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1327

主题

3834

帖子

0

粉丝