读懂C语言const限定以及复杂定义

这两天看代码的时候注意到这样的函数原型:

int getopt_long (int ___argc, char *__getopt_argv_const *___argv,
                        const char *__shortopts,
                        const struct option *__longopts, int *__longind)

其中第二个参数中的 __getopt_argv_const是一个宏,根据不同的情况,可以是const或是空白。在调用处传入的是一个char **的指针。我印象中const 与 char * 和 char **的组合总令我迷茫,也总是似看懂又不懂的过着。

1. const 限定符

const并不能把变量变成常量!而且如下定义:

const int a = 5;

只是限定了变量a为只读的,即不可以有类似的a=6的赋值操作。它并没有定义了一个常量a,也就是说在必需要常量表达式的地方不能用a,比如case a:之类的。

2. char ** 与 const char **

翻了一下 C专家编程 在第一章里就有对此问题的一个分析:

foo(const char **p){}

main(int argc, char **argv)
{
    foo(argv);
}

编译时,编译器会给出报警信息,说参数与原型不匹配。

究其原因,参数传递的过程,一定程度上可以理解为用实参给形参赋值的过程。如果这个赋值操作是非法的,则参数的传递也是有问题的。也就是说:

char **p    
const char **p1;
p1 = p;

上面的赋值,编译器会报警。

关于指针赋值:

两个操作数都是指向有限定符或无限定符的相容类型的指针,左边指针所指向的类型必须具有右边指针所指向类型的全部限定符。

而将char **p 赋值给 const char **p1来说,是不满足赋值条件的。要理解这个就需要能够读懂const char ** 与 char ** 分别定义了两个什么样的变量。

3. 阅读变量定义:

C语言有一个原则,力求定义与使用一致。即:一个变量定义的时候是什么样的形式,使用的时候也是什么样的形式。如下示例:

char *p

可以理解为其定义了一个指向char类型的指针,也可以这么理解,它定义了一个形式为*p的char类型的变量。即在需要使用char类型的时候 *p这样的形式就表示了一个char类型。(当然,常规的理解为对p进行解引用,得到其指向的char)后一种理解有助于读懂const限定的定义,例如:

const char *p,它是定义了一个只读的char类型的指针吗?显然不是的,它定义的是一个指向只读的char类型的无限定符的指针。通俗点儿讲就是,它定义了一个指针,这个指针指向了只读的char,也就是说不能对它指向的内容进行修改(赋值)操作。即: *p = 'a'这样的操作是不行的。用上面的第二种理解很容易解释,第二种理解这个定义为:*p 是一个 const限定下的char类型,将*p做为一个整体看做一个变量,这个变量是const char。这下世界清静了。

同样的,对于以下几种定义

const char **p;       **p 是const char, 那么 *p不是const 的指针, p也不是const 的指针。

char const **p;       同上面的定义一样,只是将const限定符放在了后面。

char * const *p  *p 是一个const限定的char *, 也就是说*p是一个只读的指针,而该指针指向 char; p -> (const (char *)) - > char。即无法对*p赋值,但可以对 p 以及 **p赋值。

 

4. 相容性的传递

读懂了定义之后,需要理解为何如下的赋值为报警还有一个问题就是相容性是不能传递的。

char **p;
const char **p1;
p1 = p;

上面的赋值会报警,而下面的赋值却不会:

char *p;
const char *p1;
p1 = p;

第二种情况,左值是p1, 它是一个指向只读的char的指针。它本身没有限定符,它指向的内容有const 限定符。右值p是一个指向没有限定符的char的指针,它指向的内容没有限定符。

这个赋值符合标准中规定的左值类型与右值类型相容,即都是指针,且都是指向char类型的指针。并且左值指向的类型有const限定符,左值包含了右值所有的限定符(右值没有限定符)。

 

第一种情况则不同,在第一种定义下,*p1 = *p是可以的,它等同于第二种情况的赋值。但是去掉解引用之后的p1 = p则不行了。即相容性是不能传递的。

我是这么理解的,做编译器的那帮人只允许一层嵌套,不允许两层嵌套。这一点没有办法,虽然个人觉得应该是可行的,但是编译器的实现是别人做的,除非自己做个编译器自己玩。。。

posted @ 2014-04-16 11:31  洒淡人生  阅读(990)  评论(0)    收藏  举报