虽然
(1) int* a;
(2) int *a;
都能编译通过,不过我想这是编译器的纠错优化,给许多编码潦草的人一个很大的容错度。
但是,这并不代表原本的含义就是可以随意跟随。
我的观点是正确的应该是(2)。
我看过一些帖子,有人认为(1)是正确的,理由是:int*代表了一个类型,这种说法面临的最大质疑是,倘若真如此,那么如下写法应该表示定义了三个指针变量
int* a,b,c;
但实际上我们知道不是。
另外,若int*代表了一个类型,那我们很容易想到,int*&是否又代表回了int类型呢?但实际上这样的写法编译器是不认的。
再有,若int*代表了一个类型,那转定义的时候为什么不能写成
typedef (int*) PINT;
呢?但却可以写成
typedef int (*PINT);
这实际上更强烈的暗示,我们并不是将int*定义成了PINT,而是将*PINT定义成了int。
还有
typedef char ARRAY[10];
是合法的,但
typedef char[10] ARRAY;
是非法的。这也提示,我们是定义了一个数组大小为10的ARRAY,而这ARRAY中的一个,是定义为字符类型的。而不是将ARRAY定义为了大小为10的字符数组类型。
当然,在java里,这两种写法都是ok的,这是不是后来为了更好理解的原因,想强制纠正成(1)的理解,这是另外的话题。
那支持(1)的规则到底是什么呢?我认为很混乱了。首先多引入了许多代表指针、双重指针、多重指针的类型;其次,又规定跟随&是不合法的;又规定只能适用于定义变量,而不适用于转定义类型,不适用于定义数组等等。
我认为,一个好的规则,是要尽量的简单,如果用已有的规则已经能解释清楚了,就没必要再引入新的规则。
这在哲学上叫做奥卡姆剃刀原理,即:如无必要,勿增实体。因此,(1)的规则,是不好的规则,至少在编译器所能支持的语法规范里是如此。
现在我来说说我理解的(2)的规则:
在(2)这种写法里,类型还是int,并没有增加。*a代表a取内容,这也是既有的规则。因此,它说的是,变量a的值所在的地址里,存储的是类型为int的值。因此,a被通俗地称为指向int型的指针。
在这里,没有引入额外的概念(即int*)就让人明白a到底是什么东西了。
同样,在typedef int (*PINT);
里,我们定义的还是基本类型int,没有引入额外的类型。数组的定义也是如此。
那我们再来看看,用规则(2)是怎么解释,为什么形如
int &*a;
的写法是错误的。此时,我们定义了一个变量a,它的值所在的地址里的值,再取地址……等等,这里我们就碰到问题了,无法继续理解下去。
譬如a=0x1234,在内存地址为0x1234的地方,假设值为0x5678,0x5678取地址?但,0x5678只是一个数值,不是变量,怎么取地址呢,所以是错误的声明。
但是按照(1)的规则,我们完全应该可以这样写
int*& a;
这无非是定义了一个变量a,它的类型是int*&,至于int*&是什么东西,管我什么事。再说编译器也没有提示我它不认识int*&啊。
同样的,在转定义函数指针的时候,也可以按照(2)的规则,很简单的理解定义的内容,比如
typedef int (*func)(void);
这表示函数返回值所在的内存地址里,表征的是int类型的值。我们无法写成
typedef (int*) func(void);
综上所述,个人认为,基于当前C编译器支持的语法而言,引用奥卡姆剃刀原理的话,只有(2)规则才是正确的理解。
我个人在看一些复杂定义的时候,都是通过(2)这样的规则去理解的,从来没有出现过错误。所以我也一直沿用(2)的写法。
最后,我想说的是,从谁更加容易被理解的角度,实际上(2)的规则并没有(1)来的好,我个人更希望是这样的规则
int* a,b,c; 定义了3个指针变量
char[10] array; 定义数组
typedef (int*) PINT; 是转定义类型
这显得更直观,但无奈目前编译器不是这么想的。
以上为一家之言,若有理解不对的地方,请大家指正。
原文:
http://bbs.csdn.net/topics/390442206