《再再论指针》后记

 

  在这篇后记中,笔者将对三个问题进行补充:

一、关于数组名取地址的问题。c89、c99允许对数组名取地址,是由于数组符合一个对象的定义,按照一

        个对象的语义,对其取地址是合理的。但矛盾在于,数组名是一个符号地址,是一个右值,对其取地址不

        符合&运算符的语法。c89、c99委员会经过权衡,认为维护一个对象的合理性比一个运算符更重要、更合

        理,因此允许对数组名取地址。但是,&a的意义,已经不是对一个数组名取地址,而是对一个数组对象取

        地址,因此,&a所代表的地址值才跟a地址值一样,同时sizeof(&a)应该等于sizeof(a)。c89、c99对这个

        观点是这样阐述的:

        Some implementations have not allowed the & operator to be applied to an array or a function.(The construct was permitted in early versions of C, then later made optional.) The C89 Committee endorsed the construct since it is unambiguous, and since data abstraction is enhanced by allowing the important & operator to apply uniformly to any addressable entity.

二、对于二级const指针间的赋值,笔者曾经在第九章举了一个例子,以说明二级const指针间的赋值会导

        致一个常量被修改。这里再补充一条理由。以const int *p1和int *p2为例类型比较涉及两个方面。首先,p1

       和p2所指向的对象都是int,这是相容的;p1带有const而p2没有,这也是相容的,因为它符合“指针间赋

       值左值要包含右值所有的限定词”这条规则。但对于const int ** p1和int **p2来说,情况就不一样了。虽然

       p1仍然符合“左值包含右值所有限定词”规则,但p1所指向的对象是一个指向const对象的指针,而p2所指

       向的对象却是一个指向非const对象的指针,两者的类型不相容,因此p1=p2非法。这条理由是一种已过时

       的现象,更多地存在于早期的编译器里,由于它往往让用户难以理解,因此后期的编译器都倾向于允许这种

       赋值。

三、关于p()与(*p)()之间的争论,有人提出,由于c89存在一条隐含声明,会使得p()这种形式存在危险

        性。

        首先,c89、c99推荐使用p()这种形式已经是盖棺定论的事实,两个标准是这样说的:

        Pointers to functions may be used either as (*pf)() or as pf(). The latter construct, not sanctioned in K&R, appears in some present versions of C, is unambiguous, invalidates no old code, and can be an important shorthand. The shorthand is useful for packages that present  only one external name, which designates a structure full of pointers to objects and functions: member functions can be called as graphics.open(file) instead of (*graphics.open)(file).
...........................
        The C89 Committee saw no real harm in allowing these forms; outlawing forms like (*f)(), while still permitting *a for a[], simply seemed more trouble than it was worth.

可见(*p)()这种形式是K&R时代的旧式规定,c89、c99仍然支持它只不过是因为对旧代码的支持。

        第二,这些人以为,未声明p而使用p()的时候,由于这条隐含声明的存在,p就是已被声明了,这是对隐

        含声明的错误理解,实际上c89、c99只是把这种情况下的p()当作extern int p();而已,在语法上,p仍

        然是一个未声明的标识符!它违反了另一条规则:一个标识符应当在声明之后才能使用。但它不应该象其

        它未声明标识符那样产生一条error,否则隐含声明跟不存在没有什么两样。它应该产生一条warning,以

        说明p是undefined或者函数原型未声明。

        如果一定要说会产生什么问题的话,那就是可能会有某些程序员忽略这个warning,这会产生一些问题。

        但这是设计者的原因,不是标准的原因。出于杜绝这种隐患的原因,c99干脆废除了c89的隐含声明,以使

        编译器产生一条error。c99关于这一点是这样说的:

        The rule for implicit declaration of functions has been removed in C99.The effect is to guarantee the production of a diagnostic that will catch an additional category of programming errors.

第四点写于11月8日

第四。第十章笔者解释了函数的返回值不能为数组的原因,文中笔者是这样写的:

int func(void) [5];

func是一个返回值为具有5个int元素的数组的函数。但C语言的函数返回值不能为数组,这是因为如果允许函数返回值为数组,那么接收这个数组的内容的东西,也必须是一个数组,但C语言的数组名是一个右值,它不能作为左值来接收另一个数组,因此函数返回值不能为数组。

以上这个解释有偏差,不应当用数组名来解释这个问题,因为数组名不是数组对象的引用,在C中,没有对数组对象的引用,因此,函数的返回值不能为数组。

你可能感兴趣的:(C++,c,C#,F#)