首页 > 代码库 > 令人纠结的两行代码

令人纠结的两行代码

我的主力博客:半亩方塘

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

主要参考资料:我在 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++ 语言 右值 规范上的差别,对于这点理由欢迎提供不同参考意见。