C/C++中的const
1 C中的const
C中const
修饰的变量是只读变量,在使用const
关键字声明定义变量时会给该变量分配内存空间。
const
修饰的全局变量默认是外部链接的,即其它源文件可以直接使用该变量。
const
修饰的局部变量存储在栈区中,不能通过变量名直接修改该变量的值,但是可以通过指针的方式修改该变量对应的值,从某种意义上来说,C中const
修饰的变量不是真正意义上的常量,可以将其当作一种只读变量。
C中const示例:
// fun.c
// c中const修饰的全局变量默认是外部链接的
const int num = 100; // a的本质是只读的变量,存放在文字常量区(内存空间只读)
// main.c
#include <stdio.h>
// 对fun.c中的a进行声明(不要赋值)
extern const int num;
void test()
{
printf("num = %d\n", num);
// num = 200; // error: assignment of read-only variable 'num'
}
int main(int argc, char *argv[])
{
test();
return 0;
}
#include <stdio.h>
void test()
{
const int data = 200; // 局部只读变量,通过指针的形式修改data变量的值
printf("data = %d\n", data); // 200
int* p = (int*)&data;
*p = 300;
printf("data = %d\n", data); // 300
}
int main(int argc, char *argv[])
{
test();
return 0;
}
总结:
const
修饰全局变量时,该变量存储在文字常量区(只读),不能通过指针的方式修改其内容const
修饰局部变量是,该变量存储在栈区中(可读可写),通过指针的方式可以修改其内同
2 C++中的const
C++中const
修饰的变量不需要创建内存空间,比如定义常量const int data = 10;
,C++会在一张符号表中添加name
为data
,value
为10的一条记录,如下图所示:
既然,const
修饰的变量没有内存空间,所以在C++中const
修饰的变量才是真正意义上的常量。
C++中定义声明的全局常量是内部链接的,只能作用于当前的整个文件中,如果想让其它源文件对该常量进行访问的,必须加extern
关键字将该常量转换成外部链接。
在C++中,是否为const
常量分配内存空间依赖于如何使用,以下情况会对常量进行内存空间的分配:
- 对
const
常量取地址时 - 使用变量的形式初始化
const
修饰的变量时 const
修饰自定义数据类型(结构体、对象)时
C++中const示例:
// fun.c
// const修饰的全局变量,默认时内部链接,不能直接被其它源文件使用
//const int num = 100;
// 可以通过将num转换成外部链接的方式,供其它源文件对num的访问
extern const int num = 100;
// main.c
#include <iostream>
using namespace std;
extern const int num;
struct Person{
int num;
char name[32];
};
void test()
{
cout << "全局num = " << num << endl; // error: undefined reference to `num'
// 1. c++中对const修饰的基础类型的变量不会开辟内存空间,只是将其放到符号表中
const int data = 100;
// data = 200; // error: 只读
cout << "data = " << data << endl;
// 2. 对data取地址时,系统会给data开辟空间
int* p = (int*)&data;
*p = 2000;
cout << "*p = " << *p << endl; // 2000
cout << "data = " << data << endl; // 100
// 3. 通过变量的形式初始化 const修饰的变量,系统会为其开辟空间
int a = 200;
const int b = a; // 系统直接为b开辟空间,不会把b放入到符号表中
p = (int*)&b;
*p = 3000;
cout << "*p = " << *p << endl; // 3000
cout << "b = " << b << endl; // 3000
// 4. const修饰自定义类型的变量,系统会分配空间
const Person per = { 100, "viktor" };
// p1.num = 1000; // error
cout << "num = " << per.num << ", name = " << per.name << endl; // 100, viktor
Person* p1 = (Person*)&per;
p1->num = 2000;
cout << "num = " << per.num << ", name = " << per.name << endl; // 2000, viktor
}
int main(int argc, char *argv[])
{
test();
return 0;
}
总结:
- C++中,使用
const
定义声明变量时,该变量会先放入到符号表中,不会开辟内存空间; const
修饰的全局变量默认是内部链接的;- 对
const
修饰的变量进行取地址操作,系统会对该变量开辟空间; - 使用其它的变量对
const
修饰的变量进行初始化时,系统会对该变量开辟空间; const
修饰自定义的数据类型,系统为自定义数据开辟空间。
3 C/C++中const异同总结
3.1 const修饰全局变量
全局变量存储在只读的文字常量区,所以C/C++中const
修饰的全局变量都不可以更改变量对应的内容。
C中const
修饰的全局变量默认是外部链接的,而C++中默认的是内部链接,如果想使得其变为外部链接可以在const
修饰的全局变量前加extern
关键字。
3.2 const修饰局部变量
const
在修饰基础数据类型的局部变量时,在C中会给该变量在栈中开辟内存空间,可以通过指针的方式修改变量的内容;而C++对于const
修饰基础类型的变量是在符号表中添加一条记录,不会在栈中开辟空间,所以不能通过指针的方式修改变量的值。
C++中对const
修饰的局部变量是在如何使用的情况下才分配内存,如果对const
修饰基础数据类型的局部变量进行取地址操作,会对变量分配内存;使用一个变量初始化const
变量时会分配内存;const
修饰的自定义数据类型(结构体、对象)会分配内存。
4 const和#define
在旧版本C中,如果想创建一个常量,必须使用预处理器#define MAX 1024;
。使用宏定义的MAX
对于编译器来说不知其的存在,因为在程序预处理的过程中,所有的MAX
已经被替换为1024,于是MAX
并没有将其加入到符号表中。
如果使用这个常量获得一个编译错误信息时,可能会带来一些困扰,因为这个信息可能会提到1024,但是并没有提到MAX
。
此外MAX
如果被定义在另外一个头文件中,当前可能并不知道1024代表什么,也许解决这个问题要花很长时间。解决办法就是用一个常量替换上面的宏。
const
和#define
的区别:
const
有类型,可进行编译器类型安全检查。#define
无类型,不能进行类型检查
示例:
// 宏没有类型,const有
#define MAX 1024
const short my_max = 1024;
void func(short i)
{
cout << "short函数" << endl;
}
void func(int i)
{
cout << "int函数" << endl;
}
void test()
{
func(MAX); // int函数
func(my_max); // short函数
}
const
有作用域,而#define
不重视作用域,默认定义出到文件结尾。如果定义在指定作用域下有效的常量,那么#define
就不适用
示例:
// 宏的作用域是当前的整个文件,const的作用域以定义的情况决定
void my_func(void)
{
// 作用范围是当前复合语句
const int my_num = 10;
// 作用范围是当前位置到文件结束
#define MY_NUM 10
}
void test()
{
// cout << "my_num = " << my_num << endl; // err 不识别
cout << "MY_NUM = " << MY_NUM << endl; // ok
}
const
可以作为命名空间的成员,而如果将宏作为命名空间的成员,失去了命名空间的意义,因为宏作用于当前的文件,而不是只属于某个命名空间的
5 总结
const
由C++采用,并加进标准C中,尽管它们很不一样,在C中,编译器对待const
如同对待变量一样,只不过带有一个特殊的标记,意识是”你不能改变我“。在C++中定义const
时,编译器为它创建空间,所以如果两个不同文件定义多个同名的const
,链接器将发生链接错误。简而言之,const
在C++中用的更好。
在C++中尽量使用const
来替换宏定义,避免不必要的麻烦。
另外在C++中可以使用变量定义数组。对于C,在支持C99标准的编译器中,可以使用变量定义数组。
示例:
#include <iostream>
using namespace std;
void test()
{
int a = 10;
int arr[a];
int i = 0;
for(; i < 10; i++)
arr[i] = i;
i = 0;
for(; i < 10; i++)
cout << arr[i] << " ";
cout << endl;
}
int main(int argc, char *argv[])
{
test();
return 0;
}
C/C++中的const的更多相关文章
- C++中的const
一,C++中const的基本知识 1.C++中const的基本概念 1.const是定义常量的关键字,表示只读,不可以修改. 2.const在定义常量的时候必须要初始化,否则报错,因为常量无法修改,只 ...
- C++中的const关键字
http://blog.csdn.net/eric_jo/article/details/4138548 C++中的const关键字的用法非常灵活,而使用const将大大改善程序的健壮性,本人根据各方 ...
- C++中关于const的思考
在学习C++的过程中,经常被什么时候使用const.为什么使用const以及怎么使用const关键字这样的问题所困扰,以下是我对const的使用总结. 1.值替代 使用#define的确单缺点,第一: ...
- C与C++中的const
同样,有下面一段代码: #include <iostream> using namespace std; int main() { ; int *j = (int *) &i; * ...
- C++中加const与不加const的区别
“常量”与“只读变量”的区别. 常量肯定是只读的,例如5, "abc",等,肯定是只读的,因为常量是被编译器放在内存中的只读区域,当然也就不能够去修改它. “只读变量”则是在内存中 ...
- C++笔记019:C++中的const修饰的是一个真正的常量
原创笔记,转载请注明出处! 点击[关注],关注也是一种美德~ 程序一: 我们知道数组的下标不能为变量,必须是一个确定的值.在C语言中看程序: #define a 10 int main() { //第 ...
- C++中的const总结
CONST 一.符号常量 声明: const 类型说明符 常量名 = 常量值: const float PI = 3.1415927; //可以交换const与float的位置 符号常量在声明时一定要 ...
- C和C++ 中的const
C++中的const正常情况下是看成编译期的常量,编译器并不为const分配空间,只是在编译的时候将期值保存在名字表中,并在适当的时候折合在代码中.所以,以下代码: #include <iost ...
- c++中的const和volatile知识自我总结
学习了下c++中的const关键字,总结如下. 1.const限制一个变量不能修改其内容,如果强行修改的话,如下面代码这样子,编译就会报错,“表达式必须是可修改的左值”. int main() { c ...
- C++中的const的用法
const对象.指向const对象的指针.const指针(通过一个面试题来了解) 1.const对象 (1)关于const,很多企业的笔试.面试都会出现,很简单,就问你“const的含义?”. 我 ...
随机推荐
- NGK是如何运用IPFS分布式存储的?
整个夏季,除了天气的火热,还有的火热莫过于IPFS挖矿这个领域了.IPFS的概念火热到,你可以看到到处都在卖IPFS矿机.那么,是什么原因导致IPFS这么火呢?在这之前,我们先了解一下什么是IPFS技 ...
- 为什么建议选择居住在墨尔本CBD以南2公里内
英国房地产公司PAUL ADAMS ARCHITECT ,简称PPA(公司编号:07635831)成立于2011年,是一家成立近十年的老牌房地产公司.PAA公司一直有着自己的房地产理念,秉持房子是用来 ...
- 02.Fancy Indexing
import numpy as np x = np.arange(16) index = [3,5,8] x[index] array([3, 5, 8]) X = x.reshape(4,-1) X ...
- fixed实现遮罩层,小程序
css /** 分享微信,分享朋友圈 **/ .goods_share_mask { background-color: rgba(0, 0, 0, 0.3); position: fixed; to ...
- Lambda 表达式简介
0.预备知识 函数式接口:只包含一个抽象方法的接口. 内部类:静态.成员内部类 局部内部类 匿名内部类 1.代码 1 /** 2 * 函数式编程: 3 * lambda表达式前提: 4 * 必须是函数 ...
- go 语言 如何发送微信信息到自己手机
使用 wxmgo 包可以把微信信息发送到自己的手机上.第一步: go get github.com/rehylas/wxmgo 第二步: import ( "fmt" wxm & ...
- 剑指 Offer 62. 圆圈中最后剩下的数字 + 约瑟夫环问题
剑指 Offer 62. 圆圈中最后剩下的数字 Offer_62 题目描述 方法一:使用链表模拟 这种方法是暴力方法,时间复杂度为O(nm),在本题中数据量过大会超时. 方法二:递归方法 packag ...
- python 操作符** (两个乘号就是乘方)
一个乘号*,如果操作数是两个数字,就是这两个数字相乘,如2*4,结果为8**两个乘号就是乘方.比如3**4,结果就是3的4次方,结果是81 *如果是字符串.列表.元组与一个整数N相乘,返回一个其所有元 ...
- MyBatis(四):自定义持久层框架优化
本文所有代码已上传至码云:https://gitee.com/rangers-sun/mybatis 修改IUserDao.UserMapper.xml package com.rangers; im ...
- [学习笔记] KM算法
前言 这个东西学了我挺久了,我先奉劝各位一定要先搞清楚匈牙利算法.感谢 \(\tt jzm\) 巨佬对我耐心的讲解,因为我太弱了所以卡了很久都不懂.如果你有任何问题请在本篇博客下面留言,我会尽力解答的 ...