引入:
这些东西就写在这儿了。你有两种选择, 第一在这里看懂全部, 第二在别的地方看懂全部, 为什么呢? 因为这个你只得懂, 更是值得懂
为什么需要常量const
const 其实就是#define 的另一种解决方案, 由于#define的处于机制的是在预处理阶段而不是编译阶段(速度快而已嘛)所以就只能做纯文本代替,还有就是注意#define出来的东西都是在预处理阶段从而得到的一个好处就是这个常量不用储存空间。 加入#define IP 3 .0+ 0.1415 , 后面用到了 a = 2 * IP 好吧, 这个结果大家去试试吧, const的好处更有类型检查, 所以安全多了
深入:
常量折叠
先看如下代码
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cassert> #include <cstdlib> #include <cassert> using namespace std; int main() { const int i=0; int *j = (int *) &i; *j=1; cout<<&i<<endl; cout<<j<<endl; cout<<i<<endl; cout<<*j<<endl; return 0; }
然后再看如下代码
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cassert> #include <cstdlib> #include <cassert> using namespace std; int main() { int i=0; //少了const而已 int *j = (int *) &i; *j=1; cout<<&i<<endl; cout<<j<<endl; cout<<i<<endl; cout<<*j<<endl; return 0; }
只对代码一进行分析:看看输出就知道了, 是不是相同的地址但是输出了不同的值, 这就是常量折叠, 也就是常量i 已经变成了0折叠在了代码中, 所以当代码cout << i << endl; 实际就已经变成了cout << 1 << endl;了,
以上关于常量折叠代码来自:http://www.cppblog.com/xmli/archive/2013/02/06/134425.html
const之内存分配
c++编译器默认是不会为const变量分配内存空间的,除非有如下几种种情况:
情况一:
当const变量前面有extern修饰, 有extern就说明这个变量是一个外部连接, 也就是说有多个不同的编译单元都可以引用这个const变量, 那么就必须分配储存空间
情况二:
当需要取const变量的地址的时候就需要分配空间了,比如const int oyl = 710; int *lyo = &oyl;这种情况就必须分配内存了
情况三:
当声明一个集合的时候,如数组, const int a[] = {1, 2, 3, 4}; 那么这个时候编译器不会哈到将偌大的一堆数据放到符号表里面, 那么这个时候就会分配一堆内存, 不过这个时候内存里面的内容是不会改变的, ,,,,,, 更让我有点儿不爽的是居然在编译期间这个数组里面的值不会被当做常量, 比如想声明另一个数组 int oyl[a[2]]的时候,编译器会给你一个error的,因为我估计是在编译期间编译器不知道内存里面的值吧(纯属想想呀)
const 的安全性:
由于const是不允许改变其值得, 所以如果你有本事确定一个变量在它的生存期内的值都不会改变, 那么就鼓着勇气声明成常量吧, 因为如果你不小心改变了这个值得时候, 编译器就会打小报告的
跟const有关的指针
指向cosnt的指针
const int *oyl; 和int const *oyl;是相通的吗?这个问题的答案是从变量名oyl开始读, 先读oyl的右边再读左边, 就这样一层一层的读下去就好了, 做个实例, 以语句一位准: lyo右边没有就不读, 然后在读左边,发现是一个*, 那么就索命oyl是指针, 然后在读右边(oyl的右边的右边)还是空,那么就不读, 再然后再读左边, 发现语句一是int,那么就说明oyl是指向int的指针, 然后接着读右边(oyl的右边的右边的右边)还是空, 就不读, 再读左边发现是一个cosnt, 那么就读成(oyl是一个指针, 指向int, int 是const型的, 那么最后的读法就是oyl是指向cosnt int 的指针);当然语句二最后的读法是(oyl是指向int const 的指针), 其实我想告诉你的是这两个都挺萌的的是同一个意思这个型号的指针就是oyl的指向是可以改变的, 但是指向的那个内存里面的值是不能改变的, 就好比你可以oyl = 另一个地址, 但是你不能*oyl = 别的值
const型指针
这号指针本省就是const, 那么就是说你不能改变指向, 但是你可以改变指向的内存里面的值, 也不是很拗口,能懂的int d = 10, b = 20;int * const oyl = &d;
oyl = &b; // error
*oyl = 23; //ok指向const的const指针
int t = 10;const int * const oyl = &t;
其实我就想把你弄糊涂, 怎么这么多乱起八糟的呀。 其实这个不是什么新东西, 不就是把上面的两种情况合并了吗? 那么现在都是常量了, oyl是一个const指针, 指向的是一个const int , 这样导致的结果就是完全无法改变了, 既不能改变指向, 也不能改变指向那个内存里面的值
不知道的事
赋值和类型检查:
c++编译器的类型检查做的还是很不多的, 编译器允许const 型的指针指向非const 的变量, 但是绝对不允许普通型指针指向const常量, 因为这样就可以通过修改指针里面的值来改变那个const 常量, 显然有点儿不妥, 但是有的程序员闲的蛋疼硬是要强制转化成普通型的, 看实例吧#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cassert> #include <cstdlib> #include <cassert> using namespace std; int main() { const int tt = 20; //int * oyl = &tt; //error int * oyl = (int *) &tt; //ok cout << tt << endl; cout << *oyl << endl; *oyl = 710; cout << tt << endl; cout << *oyl << endl; }
看到了强制转化吧,结果成功转化了; 既然强制转化了, 但是后来我命名改变了oyl指向的内存里面的值, 但是为什么 tt 的值为什么没有跟着改变呢 ? 这个问题的答案就是常量折叠的问题了, 其实cout << tt << endl 的时候就已经折叠成了cout << 20 << endl这句代码了;
知道的事:
#include <iostream> using namespace std; int main() { char *oyl = "oylwan"; //*(oyl + 2) = 'b'; //表示多了这句就运行错误了 printf("%s\n", oyl); }
为什么呢? 因为编译器在编译的时候是将“oylwan“当做常量字符数组建立的, 既然是常量就别想改变了, 但是为什么又可以编译通过呢, 是因为编译器在运行的阶段是将它当做变量处理的, 我也不知道为什么, 估计是为了兼容c吧
为了解决上面这个问题可以这样做:
#include <iostream> using namespace std; int main() { char tmp[] = "oylwan"; char *oyl = tmp; *(oyl + 2) = 'b'; //表示多了这句就运行错误了 printf("%s\n", oyl); }
这样就可以正常了