作者:gfree.wind@gmail.com
博客:blog.focus-linux.net linuxfocus.blog.chinaunix.net
博客:blog.focus-linux.net linuxfocus.blog.chinaunix.net
本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
======================================================================================================
今天同事发了一个问题给我,说可以将char *变量赋给const char *变量,那么为什么char **不能赋给const char**呢?
看示例:
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- int main(void)
- {
- char *p =NULL;
- const char *cp = p;
- char **pp= NULL;
- const char **cpp = pp;
- printf("%p %p %p %p\n", p, cp, pp, cpp);
- return 0;
- }
编译:
[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。
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- int main(void)
- {
- char *p =NULL;
- const char *cp = p;
- char **pp= NULL;
- char * const *cpp = pp;
- printf("%p %p %p %p\n", p, cp, pp, cpp);
- return 0;
- }
注意红色的那行,我移动了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的修饰对象有了比较清楚的了解。