导航

常量字符串的历史遗留问题。

Posted on 2005-02-21 11:27  Panic  阅读(585)  评论(0编辑  收藏  举报
问题提出:
void main()
{
    char *const p1="show me the money\n";
    cout<<p1;
    *(p1+3)='a';
    cout<<p1;
}

可以通过编译,但是运行出错,为什么?

原因很简单,"show me the money\n"本身是一个常量字符串,在VC6.0下,系统把它放在了只读权限的内存空间。
用可读写的指针指向这块区域本身就是错误的(逻辑上),而对只读内存区域进行写操作则造成了实际的错误。

C++语法对char * ,char *const 类型指针允许指向常量字符串的宽容源自于对旧的C代码的兼容。但是这种兼容造成的代码的隐患和对开发者的困扰却是不容忽视的。
我没有查阅新的C/C++标准对这一行为的描述和处理,个人认为,对于这种代码,编译器应该至少提出一个类似:“非常量指针指向了常量”的警告,或者用一个编译开关选择是否兼容旧的C语法。
对于新的代码,还是建议使用:
const char * p= "Test";
这种形式,如果写入不可避免,建议:char p[] = "Test";
可是很遗憾的是,编译器不提供对数组越界的检测,这种检测在运行时也没有进行,除了代价太高之外,指针等一些特殊的手法(比如结构体的最后一个成员用 unsigned char a[0]以实现变长结构)也无法有效运作。
因此,为了代码的安全和效率,只能在必要的时候检查数组的越界与否,或者运用ASSERT等调试手法勉强应付。

补充一点:系统是否把一个字符串常量放在只读内存空间由选项:
/GF,/Gf决定,这个选项的详细信息请参考msdn中
/Gf, /GF   (Eliminate Duplicate Strings)
部分的说明。
表面上看,VC在_DEBUG选项下是默认开启了/GF选项。而在release下则是/Gf.