在c专家编程中出现这样一个问题
foo(const char ××p){ }
int main (int argc,char **argv)
{
foo(argv);
}
编译器是报warning的。
对此 了解一下const:
<span style="font-size:18px;"><strong>#include<iostream>
using namespace std;
int main()
{
char *a;
const char *b;
b=a;
//a=b;
}</strong></span>
使用gcc编译可以通过,但是将注释的一行加进去,就编译错误。
main.cpp:8:3: error: invalid conversion from 'const char*' to 'char*' [-fpermiss
ive]
a=b;
^
const char *b; 表示指针所指向的数据是不可更改的,所以当b=a时表示通过b指针只能读取a指针所指向数据的值而不能修改。对于a=b,a是一个对数据可读可写的指针,而b不是,如果想往a指针指向的地址改变值,对于char ×a 这个定义是允许的,而b是不允许的这就是error的问题所在。
一般为 const型不可以传递给非const,反过来可以。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面总结一下 const的用法:
1
必须初始化
const int i=1; //合法
const int j; //非法,导致编译错误
但是
const char *b; 是编译通过的
b是一个指向不可修改的内存地址,称为常量指针。对于b本身还是一个没有限定符的指针类型,所以不需要进行初始化,而上面的i和j本身是具有限定符的char类型,所以要初始化。这里还引出了一个 指针常量,
char * const c; 这是编译不通过的,这里指针是具有限定符的,表明这指针在定义时必须要初始化,以后都不会变了,但是可以对指向的内存地址进行读和写。
2在另一个文件中引用const的问题
一般放在头文件中,在定义时 const char a='a'; 在头文件 可以写作 extern const char a;这里是extern声明不需要进行初始化。
3 const 和 define的 在内存使用上的区别
const 可以节省空间,避免不必要的内存分配。 例如:
#define PI 3.14159 //常量宏
const doulbe Pi=3.14159;
double i=Pi; //此时为Pi分配内存,以后不再分配!
double I=PI; //编译期间进行宏替换,分配内存
double j=Pi; //没有内存分配
double J=PI; //再进行宏替换,又一次分配内存!
const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝(因为是全局的只读变量,存在静态区),而 #define定义的常量在内存中有若干个拷贝。
这里要解释一下为什么会有这种内存上的差异,个人觉得,就是由于define定义的常量是没有数据类型的,即完成一个立即数的读写都要分配一次内存,而const 在读写时是要到固定内存地址上读写。
而且define在展开时会有边际效应。
4 为了将第三条讲的更清楚一点,研究一下const 在定义时编译器如何给其分配内存的。
#include <iostream>
using namespace std;
int main()
{
const int a = 10;
int *b = (int*)&a;
*b = 20;
cout << "&a = " << &a << ',' << "b = " << b << endl
<< "a = " << a << ',' << "*b = " << *b << endl;
return 0;
}
结果为
&a = 0x22fed8,b = 0x22fed8
a = 10,*b = 20
很神奇,这里有个常量折叠的原理。
这个人对此有研究 http://blog.csdn.net/yby4769250/article/details/7359278
虽然定义了 const型常量,但是是可以暴力破解的,为了防止出现这种情况采用常量折叠来保证。但是编译器还是为其分配地址的,可以从上面结果输出看出a的地址。
总结:常量折叠说的是,在编译阶段,对该变量进行值替换,同时,该常量拥有自己的内存空间,并非像宏定义一样不分配空间。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
对于一开始的问题给出下面实验程序
#include<iostream>
using namespace std;
void foo(const char **p) {}
int main(int argc,char ** argv)
{
//foo(argv);
const char d='d';
char c;
const char *a;
a=&c;
a=&d;
char *e;
const char **t;
t=&a;
return 0;
}
这段程序在gnu中是编译成功的。
c专家编程中这是相容性原则,即依次类型相同。但是在其他编译器也是可以通过的。
const char ××t 表明指向的指针是 const char ×的类型,再指向const char 型的数据;
char ××argv 表明指向的指针是char× 型的,再指向char型数据;中间有不相容的类型。