令人纠结的两行代码

我的主力博客:半亩方塘

下面内容系原创,转载请务必注明地址

主要參考资料:我在 Stackoverflow 上提的问题 Why the first is right but the second is wrong ?

这令人纠结的两行代码例如以下:

const char *cval = "nothing";  // 正确
int *ival = {1, 2, 3, 4};      // 错误  

为什么第一行代码正确第二行代码错误呢?既然 "nothing" 在内存中是以数组的形式存储的,那么,为什么能够定义一个 cval 指向它而不能相应地定义一个 ival 指向以下的数组呢?这确实是一个非常让人纠结的问题,看以下的分析吧:

首先我们来看第一行代码:

const char *cval = "nothing";

赋值运算符右側是一个 字符串字面值常量 ,编译器将字符串字面值常量放在内存空间中的一段连续的地址单元进行存储,且 存储的类型为 const char[] ,存储的形式是: {'n', 'o', 't', 'h', 'i', 'n', 'g', '\0'} ,这一点非常重要,将赋值运算符右側的字符串字面值赋给左側的运算对象时,const char[] 类型将向 const char* 进行转换,因为数组名本身就是一个指针,因此这样的转换是合理的,合法的,所以这部分代码是正确的;

再来看看下面的这部分代码:

int *ival = {1, 2, 3, 4}; 

这部分代码怎么是错的了?这是由于,编译器不同意单独将 {1, 2, 3, 4} 存储到内存中,而必须将其复制到某一个对象相应的连续的地址单元,显然,赋值运算符右边仅仅是一个指向 int 的指针类型,不具备存储 {1, 2, 3, 4} 的条件,所以,这部分代码是错误的。
因为在 C 语言中,从 C99 以后,有一个称之为 compund literal 的特性,所以对于第 2 行的代码,在 C 中我们可进行例如以下改动使其正确:

int *ival = (int []) {1, 2, 3, 4};  

上面的这行代码在 C++ 中是不成立的,有错误产生,想想为什么呢?这是由于 C 和 C++ 的语言特性是不一样的,在 C 中,上面代码中的赋值运算符右側是一个持久的值,是一个常量对象,它被创建的时候有着持久的地址,可是,在 C++ 中,右側运算对象仅仅是一个暂时对象,不具备持久的地址,在 (int []) {1, 2, 3, 4} 这个表达式结束时地址已经消亡,我个人觉得,这是 C 和 C++ 语言 右值 规范上的区别,对于这点理由欢迎提供不同參考意见。


posted @ 2015-05-09 18:49  hrhguanli  阅读(224)  评论(0编辑  收藏  举报