关于 const 关键字的研究

30 篇文章 0 订阅

在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型数据;中间有不相容的类型。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值