当前位置:嗨网首页>书籍在线阅读

21-指针的兼容性

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

10.7.2 指针的兼容性

指针之间的赋值比数值类型之间的赋值要严格。例如,不用类型转换就可以把 int 类型的值赋给 double 类型的变量,但是两个类型的指针不能这样做。

int n = 5;
double x;
int * p1 = &n;
double * pd = &x;
x = n;              // 隐式类型转换
pd = p1;            // 编译时错误

更复杂的类型也是如此。假设有如下声明:

int * pt;
int (*pa)[3];
int ar1[2][3];
int ar2[3][2];
int **p2;    // 一个指向指针的指针

有如下的语句:

pt = &ar1[0][0];     // 都是指向int的指针
pt = ar1[0];         // 都是指向int的指针
pt = ar1;            // 无效
pa = ar1;            // 都是指向内含3个int类型元素数组的指针
pa = ar2;            // 无效
p2 = &pt;            // 都是指向int *的指针
*p2 = ar2[0];        // 都是指向int的指针
p2 = ar2;            // 无效

注意,以上无效的赋值表达式语句中涉及的两个指针都是指向不同的类型。例如, pt 指向一个 int 类型值,而 ar1 指向一个内含3个 int 类型元素的数组。类似地, pa 指向一个内含3个 int 类型元素的数组,所以它与 ar1 的类型兼容,但是 ar2 指向一个内含2个 int 类型元素的数组,所以 paar2 不兼容。

上面的最后两个例子有些棘手。变量 p2 是指向指针的指针,它指向的指针指向 int ,而 ar2 是指向数组的指针,该数组内含2个 int 类型的元素。所以, p2ar2 的类型不同,不能把 ar2 赋给 p2 。但是,* p2 是指向 int 的指针,与 ar2[0] 兼容。因为 ar2[0] 是指向该数组首元素( ar2[0][0] )的指针,所以 ar2[0] 也是指向 int 的指针。

一般而言,多重解引用让人费解。例如,考虑下面的代码:

int x = 20;
const int y = 23;
int * p1 = &x;
const int * p2 = &y;
const int ** pp2;
p1 = p2;        // 不安全 -- 把const指针赋给非const指针
p2 = p1;        // 有效 -- 把非const指针赋给const指针
pp2 = &p1;      // 不安全 –- 嵌套指针类型赋值

前面提到过,把 const 指针赋给非 const 指针不安全,因为这样可以使用新的指针改变 const 指针指向的数据。编译器在编译代码时,可能会给出警告,执行这样的代码是未定义的。但是把非 const 指针赋给 const 指针没问题,前提是只进行一级解引用:

p2 = p1; // 有效 -- 把非const指针赋给const指针

但是进行两级解引用时,这样的赋值也不安全,例如,考虑下面的代码:

const int **pp2;
int *p1;
const int n = 13;
pp2 = &p1;   // 允许,但是这导致const限定符失效(根据第1行代码,不能通过**pp2修改它所指向的内容)
*pp2 = &n;   // 有效,两者都声明为const,但是这将导致p1指向n(*pp2已被修改)
*p1 = 10;    //有效,但是这将改变n的值(但是根据第3行代码,不能修改n的值)

发生了什么?如前所示,标准规定了通过非 const 指针更改 const 数据是未定义的。例如,在Terminal中(OS X对底层UNIX系统的访问)使用gcc编译包含以上代码的小程序,导致 n 最终的值是 13 ,但是在相同系统下使用clang来编译, n 最终的值是 10 。两个编译器都给出指针类型不兼容的警告。当然,可以忽略这些警告,但是最好不要相信该程序运行的结果,这些结果都是未定义的。

C const和C++ const

C和C++中 const 的用法很相似,但是并不完全相同。区别之一是,C++允许在声明数组大小时使用 const 整数,而C却不允许。区别之二是,C++的指针赋值检查更严格:

const int y;
const int * p2 = &y;
int * p1;
p1 = p2; // C++中不允许这样做,但是C可能只给出警告

C++不允许把 const 指针赋给非 const 指针。而C则允许这样做,但是如果通过 p1 更改 y ,其行为是未定义的。