注销

注销

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  112 随笔 :: 7 文章 :: 18 评论 :: 0 Trackbacks
从语句 char* p="test" 说起
 
陈皓
 
 
我相信,使用 C/C++ 多年的人对下面这个字符串赋值语句都不会陌生吧。
 
              char* p = “anything”;
 
同时,我也相信,各位在使用这种语句后吃过很多苦头也不少吧?只要你想利用指针 p 来改变字符串的内容,你的程序都会到一个让你颜面尽失一个内存非法操作。比如,下面的这些语句:
 
              p[0] = ‘s’;
              strcpy(p, “haoel”);
 
原因就在于, char* p = “hello world”; 这个声明,声明了一个指针,而这个指针指向的是全局的 const 内存区 const 内存区当然不会让你想改就改的。所以,如果你一定要写这块内存的话,那就是一个非常严重的内存错误。另,之所以加粗“全局 const 内存区”,是强调一下,如果你不信的话,你可以试试下面这段代码,看看 p1 p2 的地址是不是一样的。
 
              char* p1 = “anything”;
              char* p2 = “anything”;
              printf(“ p1=%x, p2=%x \n”, p1, p2);
 
我想这应该是一个众所周知的问题吧。取而代之的,应该是使用数组来做声明。如: char str[] = “hello world”; 如果现在还有哪本书中的 C 的示例采用了这种方式,那么你就可以把那本书撕了,如果这本书是 C++ 的书话,那么你应该把这个作者和这个出版社告上法庭,因为你不应该容忍这种学术骗子。如果你的部门的开发人员还有人写出这种代码的话,如果他是 C 程序员,我想你可以在打过他的屁股后告诉他下不为例,如果他是一个 C++ 程序员的话,我想你可以怀疑他是否有资格做一个 C++ 程序员了。
 
       至于你问我为什么要对学 C++ 的人那么苛刻,那是因为学过 C++ 的人都知道 C++ 中的 const 关键字的有着什么样的权力,你也应该知道 C++ const 有着无比的照顾和关爱,几乎所有关于 C++ 的书都会提到 const 这东西。所以,如果作为一个 C++ 的程序员来说,如果你不知道的话,那就太说不过去了。
 
       我们知道,双引号引起来的字符串是 const 的,所以,在 C++ 的世界中,你应该进行如下的声明才比较稳妥:
             
              const char *p = “anything”;
 
这样,当你修改这个字符串的内容时,编译器会给你一个错误而导致你的程序编译不通过,从而不会产生运行时的内存错误。
 
       可问题是,像 C++ 这种对类型要求很严格的语言来说,为什么它在编译诸如 char *p=”anything” 程序的时候不出错,甚至连个警告都没有( g++ vc++7 )?难道这是他的一个 bug ?我想,这应该是对古老的 C 的一个向下兼容。因为,在 C 的世界中,这种用法太多了。
 
C++ 中,比如:函数的参数和异常的捕获都存在这种问题,如下所示:(因编译器而定,在 gcc 3.4.3 版中,下例中的异常示例不能被捕获,但 VC++6 中却可以被捕获)
 
       func( char* p) { }   // 以这种方式调用函数 func(“abc”);
      
       try { thow “exception”; } catch (char* p) { }
 
       这些东西,无疑会对大家是一个误导。甚至让人无所畏惧地走入其中,并自以为走入了正途。这样看来,这种向下兼容的 C++ 标准,就显得有点误人不浅了
 
       不过好在, C++ 标准委员会早已意识到了这一点。这个 C++ feature 被定义为了“ Deprecated Feature ”,即“不被建议使用的特性”。意思就是,在将来,这种特性将被从 C++ 中移出,于是,你目前的这种程序将无法在新的 C++ 编译器上编译通过。对于程序的可移植性来说,我们今天所写的代码尤其要注意这些“ Deprecated Feature ”。
 
       据我所知,目前 C++ 中被列为“ Deprecated Feature ”如下所示(可能不准确,请大家指正)
 
一、           隐晦的字符串的 const 转换。

char *p = “test”;
w_char *pw = “test”;
char p[] = “test”;
       把一个 const 的字符串类型转成 non-const 的。包括指针和数组。
 
二、           隐晦的类型声明。

func() {}   // 函数的隐晦返回类型是 int
static num;    // 变量的隐晦类型是 int
       这种 feature C89 中还可以使用,但在 C99 C++ 中都被去除了。( gcc 3.4 版本对于这种声明会给出编译错误,而 VC++6.0 会认为这是合法的程序)
 
三、           布尔变量的累加操作。
bool isConn = false;
isConn++;          // 这个操作会把 isConn 变为 true
就目前而言,几乎所有的编译器都认可这种操作,但这种用法也是不被建议的,终有一天会被取消。
 
四、           更改父类成员的存取权限。
 
class B
{
    protected:
        int i;
};
 
class D : public B
{
     public:
        int i;
};
 
       对于这种语法,一般来说,编译器会把了类中的那个重复的变量认为成两份。
也就是说,父类的和子类的各是各的。这个 feature 对于所有的编译器来说应该都是可以编译通过的(连个 Warning 都没有)。但这个 feature 也是要被废除的。
 
五、           文件中域的 static 声明
 
static int i;
static void func()
 
       据说,这种旧的在 C 中的为了实现其作用域在本文件中的 feature 在未来的 C++ 中也要被取消。
 
 
文章到这里应该结束了,在结束之前,让我再给大家共享一个有趣的关于 const 的例子(在网上看到的)
 
    const int a = 1;
    int *p = const_cast<int*>(&a);
    *p = 2;
 
    cout << “value a=”<< a << endl;
    cout << “value *p=” <<*p << endl;
    cout << “address a=” <<&a << endl;
    cout << “address p=” <<p << endl;
这段代码输出的结果如下:
 
value a=1
value *p=2
address a=0xbff1d48c
address p=0xbff1d48c
 
地址都是一样的,可值为什么不一样呢?呵呵。这个问题看起来有点“学术味”过浓,不过是个好例子,可以让你知道 C++ 的一些用法和一些原理。有以下几个方面大家可以考虑一下:
1) const int a = 1 是不是和宏有点像,会不会被编译器优化了?
2) 去修改一个 const 的值,本来应该是不对的。这可能会是向旧的 C 兼容。是否会让编译器产生未知行为?
 
所以,这个示例也告诉我们,我们应该遵循 C++ 中的 const non-const 的语义,任何想要破坏这个语义的事情都会给我们带来未知的结果。
posted on 2006-11-19 10:50 注销..... 阅读(428) 评论(0)  编辑  收藏 所属分类: c++

只有注册用户登录后才能发表评论。


网站导航: