引入
我们用两个简单(?)的问题作为引入,当然我们整篇文章都会围绕这两个问题:
- 下面四种类型声明等价吗?
int* i;
int *i;
int * i;
int*i;
- 下面四种类型声明中,
j
拥有哪一个数据类型?是int
或者int
的指针?int* i, j;
int *i, j;
int * i, j;
int*i, j;
当然看到这里,如果你已经有非常自信的答案,你当然可以无视这一篇文章后面的部分。
第一个问题
第一个问题的答案是: 四种指针的类型声明的等价的。
很好,既然我们知道它们等价,或许已经足够了。但是我们数据库教授总是在课上提醒大家,知道区别并不足够,还需要问自己其中的哪一个更好,什么情况下用哪一种方式。
哪一种写法更好呢?
C++之父在他的一篇文章:Bjarne Stroustrup's C++ Style and Technique FAQ中提到:
The choice between
int* p;
andint *p;
is not about right and wrong, but about style and emphasis. C emphasized expressions; declarations were often considered little more than a necessary evil. C++, on the other hand, has a heavy emphasis on types.A
typical C programmer
writesint *p;
and explains it*p is what is the int
emphasizing syntax, and may point to the C (and C++) declaration grammar to argue for the correctness of the style. Indeed, the * binds to the name p in the grammar.A
typical C++ programmer
writesint* p;
and explains itp is a pointer to an int
emphasizing type. Indeed the type of p is int*. I clearly prefer that emphasis and see it as important for using the more advanced parts of C++ well.
</br>
Linux kernel coding style中的习惯规则是:
When declaring pointer data or a function that returns a pointer type, the
preferred use of*
is adjacent to the data name or function name and not
adjacent to the type name. Examples:
char *linux_banner;
unsigned long long memparse(char *ptr, char **retptr);
char *match_strdup(substring_t *s);
某种程度上它也拟合了C++之父Bjarne Stroustrup的想法。
第二个问题
第二个问题的答案是: j
的类型是int
。
当然这问题是编译器的行为,或者语言自身的规定,很难去阐述行为或规定背后的为什么。
我们继续看Bjarne Stroustrup's C++ Style and Technique FAQ,这部分紧接问题一中对应的引用:
The critical confusion comes (only) when people try to declare several pointers with a single declaration:
int* p, p1; // probable error: p1 is not an int*
Placing the * closer to the name does not make this kind of error significantly less likely.
int *p, p1; // probable error?
Declaring one name per declaration minimizes the problem - in particular when we initialize the variables. People are far less likely to write:
int* p = &i;
int p1 = p; // error: int initialized by int*
And if they do, the compiler will complain.
从他的这一部分文字中,很容易可以看出我们这文章中的第一个问题和第二个问题完全是紧密结合。第二个问题中的四种写法的确是等价的,但是无一能让人轻松理解。从他的这一个观点中:Declaring one name per declaration minimizes the problem
,我们可以对这篇文章下一个主观的结论。
结论
针对第二个问题,对我来说最好的方式是:
int* i;
int j;
这种写法更清晰,也是多个Stackoverflow提问中所提倡的。
最后一点声明是,无论怎么写对编译器来说其实都无所谓,它只是客观地去检查能否通过编译然后生成对应的代码。这些等价写法对应的汇编语言甚至一样,对应的程序的效能自然也是一样。这些写法迷惑的只是人类(编程的人和浏览代码的人),我们需要有一个清晰的方式,保证自己不出错同时也让代码浏览者能快速理解。
</br>
</br>
引用和推荐阅读:
http://www.stroustrup.com/bs_faq2.html#whitespace
https://www.kernel.org/doc/Documentation/process/coding-style.rst
https://softwareengineering.stackexchange.com/questions/7305/int-i-or-int-i-or-int-i
https://stackoverflow.com/questions/6990726/correct-way-of-declaring-pointer-variables-in-c-c
https://stackoverflow.com/questions/13894228/where-to-put-the-star-in-c-and-c-pointer-notation
https://stackoverflow.com/questions/2704167/type-declaration-pointer-asterisk-position
https://stackoverflow.com/questions/180401/placement-of-the-asterisk-in-pointer-declarations
(Stackoverflow统统是在问同一件问题)
该文章遵循创作共用版权协议 CC BY-NC 4.0,要求署名、非商业 、保持一致。在满足创作共用版权协议 CC BY-NC 4.0 的基础上可以转载,但请以超链接形式注明出处。文章仅代表作者的知识和看法,如有不同观点,可以回复并讨论。