在 C89/90 中,由于规定左值数组才能进行数组到指针的转换,因此 A 中的
fun( &T ).a 不能在表达式中进行从数组类型到指针类型的转换,A 中的
fun( &T ).a 是非法的,但 C99 在上述条款中不再限定左值表达式,即对这个
转换不再区分左值还是右值数组,因此都是合法的;C 中的 fun( &T ).a 是
sizeof 运算符的操作数,这种情况下 fun( &T ).a 并不进行数组到指针的转换,
因此 C 在所有 C/C++标准中都是合法的;B 初看上去仍然有点诡异,&运算符
不是已经作为例外排除了数组与指针的转换吗?为什么还是非法?其实 B 违反
了另一条规定,&的操作数要求是左值,而 fun( &T ).a 是右值。C++继承了
C99 的观点,也允许右值数组的转换,其条款非常简单:
An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can
be converted to an rvalue of type “pointer to T.” The result is a pointer to the first
element of the array.
数组类型到指针类型的转换与左值到右值的转换、函数类型到指针类型的
转换一起是 C/C++三条非常重要的转换规则。C++由于重载解析的需要,把
这三条规则概念化了,统称为左值转换,但 C 由于无此需要,只提出了规则。
符号是语言对计算机的高级抽象,但计算机并不认识符号,它只认识数值,因
此一个符号要参加表达式计算必须先对其进行数值化,三条转换规则就是为了
这个目的而存在的。
看到这里,大概有些初学者已经被上述那些左值右值、对象非对象搞得稀
里糊涂了。的确,数组与指针的复杂性让人望而生畏,不是一朝一夕就能完全
掌握的,需要一段较长的时间慢慢消化。因此笔者才将数组与指针称为一门艺
术,是的,它就是艺术!
第二章 数组名是一个指针常量吗?
数组名是一个指针常量这种观点来源于数组名在表达式计算中与指针的结
果等效性。例如下面的代码:
int a[10], *p = a, *q;
q = a + 1;
q = p + 1;
在效果上看,a + 1 与 p + 1 是相同的,这很容易给人一种 a 就是 p 的假
象,但,这仅仅是假象。鉴于指针常量包含了指针和常量两类概念,我们可以
把这个问题分开两部分进行讨论。