在C 中声明指针时,有 3 种变体:
变体 A:
int* ptr;
变体 B:
int *ptr;
变体 C:
int * ptr;
- 在 A 中,间接运算符已附加到类型。
- 在 B 中,间接运算符已预先添加到变量中。
- 在 C 中,间接运算符自由地介于类型和变量之间。
声明指针的方式因我阅读的文档类型而异。一些作者似乎偏爱某些变体,而另一些作者则使用几种。
- 我是否正确假设不同变体之间的功能没有差异?
- 如果是,是否有约定在 C 中应该使用哪个变体?
在C 中声明指针时,有 3 种变体:
变体 A:
int* ptr;
变体 B:
int *ptr;
变体 C:
int * ptr;
声明指针的方式因我阅读的文档类型而异。一些作者似乎偏爱某些变体,而另一些作者则使用几种。
没有其他人提到的是
int *ptr;
更接近于语言语法。
int *ptr;
是一个声明,它包括:
int
,后跟*ptr
.(这实际上跳过了许多步骤,但它传达了基本思想。)
由于声明遵循使用,这意味着它*ptr
是类型int
。由此得出ptr
类型为int*
。
有人可能会争辩说,这使它比
int* ptr;
出于同样的原因
x = y+z;
好于
x=y + z;
当然可以写
int* ptr;
并将其读作“ptr
是类型int*
”。许多程序员都这样做,而且相处得很好(它往往是 C++ 中的首选风格)。编译器不在乎你用哪种方式来做,任何阅读你的代码的人都不应该在理解它时遇到困难。
但无论您选择哪种间距,您都需要了解int *ptr;
真正的含义,这样当您看到
int *ptr, i;
在别人的代码中(你不可避免地会这样),你会立即明白那ptr
是一个指针并且i
是一个 int。
如果您正在与其他程序员一起在一个项目上工作,您应该遵循编码标准中的任何现有约定,或者如果没有,则遵循已经编写代码的方式。我个人更喜欢int *ptr;
,int* ptr;
但混合使用这两种风格远不如始终使用其中一种风格。
两者在功能上绝对没有区别
int* ptr;
和
int *ptr;
您使用哪种取决于您,有多种相互冲突的编码样式可供选择。
T *a;
is the preferred C style for declaring a pointer to T
as used in Kernighan & Ritchie's book about C, as well as in ISO/IEC 9899:2018.
T* a;
is the preferred C++ style way to a declare pointer to T
as used in Stroustrup's book about C++.
Both notations are equivalent.
仅当您计划在同一行上声明多个相同类型的变量时才重要。例如,如果你想要多个 int 指针,你需要这样做:
int *a, *b, *c;
但是,从风格上讲,当您只声明一个变量时,这会让人感到困惑。很多人喜欢看类型后跟变量名,而类型应该是指向 int 的指针,而不是 int,所以他们更喜欢:
int* a;
int* b;
int* c;
最终取决于您是否更喜欢一种形式而不是另一种形式。在 20 年的专业 C 编程生涯中,我看到大约 50% 的人选择其中之一。
他们的意思和其他人说的一样。不过有一个陷阱在等着你。考虑这段代码:
int* a, b;
您可能认为 this 声明了指向int
. 不是这样,否则。事实上a
是int*
但是b
是int
。这是许多 C 程序员更喜欢将*
next 放在变量而不是类型的原因之一。当这样写时:
int *a, b;
你不太可能被误导什么a
和b
是什么。
说了这么多,许多编码标准坚持每行声明不超过一个变量,即
int* a;
int b;
如果您遵循每行一个变量的规则,那么绝对没有混淆的余地。
C 声明基于表达式的类型,而不是对象。
如果你有一个指向int
named的指针pi
,并且你想访问它指向的整数值,你必须取消对指针的引用,如下所示:
x = *pi;
printf("%d", *pi);
*pi = 1 + 2;
等等。表达式 *pi
的类型是int
:因此,声明应该读作
int *pi;
char
现在让我们假设你有一个指向;的指针数组。要获取任何字符,您需要先对数组下标,然后取消引用结果:
c = *pc[i];
if (*pc[j] == 'a') {...}
等等。同样,表达式 *pc[i]
的类型是char
,所以声明读作
char *pc[N];
两者*pi
和*pc[N]
都称为声明符,并指定类型说明符未给出的附加类型信息。IOW,array-ness 和 pointer-nesspc
被指定为声明符的一部分,而char
-ness 由类型说明符给出。
至于哪种风格合适的问题......
两者都不是“正确的”,但我(和许多其他 C 程序员)更喜欢写T *p
而不是T* p
,因为它更接近地反映了语言语法(*
是声明符的一部分),并且在声明多个项目时有助于避免混淆。我见过太多人们写作T* a, b;
并期望b
成为指针的例子。
对这种批评的通常反应是“每行不要申报超过一项”。我对该回复的回应是“正确编写你的声明器,你不会有任何问题”。
许多 C++ 程序员有不同的思想流派,他们更喜欢这种T* p
风格,我不得不说有一些情况(仅限于 C++)它可以使代码更具可读性。
然而,这只适用于简单的指针T
:当你开始处理指针数组、数组指针、函数指针或函数指针数组的指针等时,范式会迅速崩溃。我的意思是,写一些东西喜欢
T* (*(*p)[N])(); // p is a pointer to an array of pointers to functions
// returning pointers to T.
只是表示思维混乱。虽然,如果你真的真的觉得你必须遵循T* p
范式,你总是可以创建一系列 typedef:
编辑
让我们再试一次:
typedef T* TPtr; // pointer to T
typedef TPtr TPtrFunc(); // function returning pointer to T
typedef TPtrFunc* TPtrFuncPtr; // pointer to function returning
// pointer to T
typedef TPtrFuncPtr TPtrFuncPtrArray[N]; // N-element array of pointer to function
// returning pointer to T
TPtrFuncPtrArray* p;
看在上帝的份上,不要那样做。
在 C 中,空格无关紧要,除非在需要分隔标记的地方。您的两个变体在语法上都是正确的。
变体 1 将指针运算符与类型相关联,这足够合乎逻辑。对我来说,如果没有变体 2 有意义的原因,那就足够了。
变体 2 与 C 声明的结构方式一致。在 C 语法中,指针运算符属于声明符(即带有名称),而不是类型。这在同一个声明中声明多个变量时很重要。还有一些更深奥的案例很重要。
因此,对我来说,变体 2 与 C 更一致。但是任何一个变体都是可辩护的,并且两个变体都是常规的。
您是对的,两者对编译器的含义完全相同。两个语句都会产生一个类型为 的变量(int *)
。
至于哪个是正确的:蠕虫罐头!这通常是一个辩论话题。如果您在一家公司或 OSS 工作,最好遵循已定义的编码风格。如果没有,我通常会采用 LNT(不留痕迹)风格来匹配这部分代码库中明显使用的任何风格。
可以说,对于读者来说,一个更容易理解。例如int* ptr;
,*
越接近可以int
更清楚地传达我们正在谈论的(int *)
类型......