Chinaunix首页 | 论坛 | 认证专区 | 博客
  • 博客访问: 264670
  • 博文数量: 181
  • 博客积分: 130
  • 博客等级: 入伍新兵
  • 技术积分: 587
  • 用 户 组: 普通用户
  • 注册时间: 2011-01-12 19:39
文章分类

全部博文(181)

文章存档

2018年(2)

2016年(10)

2015年(6)

2014年(31)

2013年(96)

2012年(36)

我的朋友
微信关注

IT168企业级官微



微信号:IT168qiye



系统架构师大会



微信号:SACC2013

作者:gfree.wind@gmail.com
博客:blog.focus-linux.net   linuxfocus.blog.chinaunix.net
 
 
本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
======================================================================================================
今天同事发了一个问题给我,说可以将char *变量赋给const char *变量,那么为什么char **不能赋给const char**呢?

看示例:
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>

  4. int main(void)
  5. {
  6.     char *p = NULL;
  7.     const char *cp = p;
  8.     char **pp = NULL;
  9.     const char **cpp = pp;


  10.     printf("%p %p %p %p\n", p, cp, pp, cpp);

  11.     return 0;
  12. }
编译:
[fgao@fgao-vm-fc13 test]$ gcc -g -Wall test.c
test.c: In function ‘main’:
test.c:10: warning: initialization from incompatible pointer type

测试结果确实是这样。下面说说原因。

其实warning已经明确的告诉了我们原因,之所以无法将char **赋给const char**,就是因为指针类型不同。那么为什么char *与const char*也是仅差了一个const,却可以呢。根本原因就在于const限定符究竟对起作用,以及指针的类型到底是什么。

首先,我们要看指针类型到底是怎样定义的。下面是C99标准中的定义
—A pointer type may be derived from a function type, an object type, or an incomplete
type, called the referenced type. A pointer type describes an object whose value
provides a reference to an entity of the referenced type. A pointer type derived from
the referenced type T is sometimes called ‘‘pointer to T’’. The construction of a
pointer type from a referenced type is called ‘‘pointer type derivation’’.
指针的类型取决于它指向的对象。

对于char *p,p的类型即为指向char的指针;const char * cp呢,这里的const修饰的是char,那么cp的类型即为指向const char的指针,也就是说cp并不是常量。也可以写为char const *cp,这时const仍然修饰的是char而不是cp。如果要定义一个常量指针,要写为char * const cp。

根据C99标准
For any qualifier q, a pointer to a non-q-qualified type may be converted to a pointer to
the q-qualified version of the type; the values stored in the original and converted pointers
shall compare equal.
对于char *p和 const char *cp来说,根据上面的说明,是可以将p赋给cp的。


对于char **pp,pp的类型为指向char型的指针的指针;而const char ** cpp呢,根据前面关于const的说明,这里的const仍然是修饰的是char,那么cpp的类型为指向const char型的指针的指针。因此pp和cpp完全是两个不同的类型的指针,所以会产生warning。

是不是还是有点模糊啊,呵呵。那么下面,我再换一种说法,按照指针类型定义,指针的类型为指向类型T的指针。对于char **pp,其类型为指向类型T1的指针,T1的类型为指向char型的指针;而const char**cpp,其类型为指向类型T2的指针,T2的类型为指向const char型的指针。很明显,T1和T2是不同的指针类型,因此当把pp赋给cpp时,其类型不同导致产生warning。

不知道现在是否说清楚了呢?为了说的更清楚一些,我对上面的例子做一点小改动,来消除warning。
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>

  4. int main(void)
  5. {
  6.     char *p = NULL;
  7.     const char *cp = p;
  8.     char **pp = NULL;
  9.     char * const *cpp = pp;


  10.     printf("%p %p %p %p\n", p, cp, pp, cpp);

  11.     return 0;
  12. }
注意红色的那行,我移动了const的位置,从而改变了const修饰的内容。
编译:
[fgao@fgao-vm-fc13 test]$ gcc -g -Wall test.c
没有任何warning。

char * const *cpp 与 const char ** cpp,类型完全不同。后者前面已经说了。前者的类型为,指向char的常量指针的指针。也就是cpp的类型为指向常量T3的指针,而T3为指向char型的指针。这时cpp与pp的指向的类型仅限于限定符的不同,因此可以将pp赋给cpp。


我相信如果大家看到现在应该已经明白了为什么char **不能赋给 const char**了,并且通过这个例子,也对于const及其它限定符如volatile的修饰对象有了比较清楚的了解。


注:
1. 我把解释发给了同事。后来他说《C专家编程》也有对这个问题的解释,但是他没有不是太理解《C专家编程》中的说法。我后来翻了翻,基本上上面的解释和我的解释意思相同。呵呵,看来自己对于C的语法细节理解,还是不错的呵,小小的骄傲一下——我虽然看过《C专家编程》,但是早就忘了这个解释了,此处的分析完全是自己分析的结果。
2. 我感觉语法细节不过是细枝末节,虽然挺重要,但是再掌握到了一定程度以后,再研究下去,效果貌似不大。今天正好群里有朋友发了一个C的晦涩的用法,挺离奇的,同时也不具备可读性。这让我想起了混乱C代码大赛的一些获奖作品。能写出那些代码的人,绝对是C的高手中的高手,绝对的geeker。对于普通人的我,虽然很感叹那么细节的用法,但是对我的吸引力还是把基本的C的细节搞清即可。不过以后,连C都不敢说精通了,唉~。


阅读(487) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册