关于ANSI C标准的一点收获

有时候必须非常专注地阅读ANSI C标准才能找到某个问题的答案。一位销售一程师把下面这段代码作为测试例发给Sun的编译器小组。

foo(const char **p){}

main(int argc,char **argv)

{

      foo(argv);

}

如果编译这段代码,编译器会发出一条警告信息:

line5:warning:argument is incompatible with prototype

(第5行:警告:参数与原型不匹配)

提交代码的工程师想知道为什么会产生这条警告信息,也想知道ANSI C标准的哪一部分讲述了这方面的内容。他认为,实参char* s与形参const char* p应该是相容的,标准库中所有的字符串处理函数都是这样的。那么,为什么实参char **argv与形参const char **p实际上不能相容呢?

答案是肯定的,它们并不相容。要回答这个问题颇费心机,如果研究一下获得这个答案的整个过程,会比仅仅知道结论更有意义。对这个问题的分析是由Sun的其中一位“语言律师”进行的,其过程如下:

在ANSI C标准第6.3.2.2节中讲述约束条件的小节中有这么一话:

每个实参都应该具有自己的类型,这样它的值就可以赋给与它所对应的形参类型的对象(该对象的类型不能含有限定符)

这就是说参数传递过程类似于赋值。

所以,除非一个const char **类型的对象可以赋值给一个类型为char **的值,否则肯定会产生一条诊断信息。要想知道这个赋值是否合法,就请回顾标准中有关简单赋值的部分,它位于第6.3.16.1节,描述了下列约束条件:

要使上述的赋值形式合法,必须满足下列条件之一:

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

正是这个条件,使得函数调用中实参char *能够与形参const char *匹配(在C标准库中,所有的字符串处理函数就是这样的)。它之所以合法,是因为在下面的代码中:

char *cp;

const char *ccp;

ccp=cp;

左操作数是一个指向有const限定符的char的指针。

右操作数是一个指向没有限定符的char的指针。

char类型与char类型是相容的,左操作数所指向的类型具有右操作数所指向类型的限定符(无),再加上自身的限定符(const)。

注意,反过来就不能进行赋值。如果不信,试试下面的代码:

cp=ccp;         /*结果产生编译警告*/

标准第6.3.16.1节有没有说char **实参与const char *形参是相容的?没有。

标准第6.1.2.5节中讲述实例的部分声称:

const float *类型并不是一个有限定符的类型——它的类型是“指向一个具有const限定符的float类型的指针”,也就是说const限定符是修饰指针所指向的类型,而不是指针本身。

类似地,const char **也是一个没有限定符的指针类型,它的类型是“指向有const限定符的char类型的指针的指针”。

由于char **和const char **都是没有限定符的指针类型,但它们所指向的类型不一样(前者指向char *,后者指向const char *),因此它们是不相容的。因此,类型为char **的实参与类型为const char **的形参是不相容的,违反了标准第6.3.2.2节所规定的约束条件,编译器必然会产生一条诊断信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值