在 C 语言中,声明指针有三种变体:
变体 A:
int* ptr;
变体B:
int *ptr;
变体C:
int * ptr;
- 在A中,间接运算符已追加到类型之后。
- 在B中,间接运算符已前置于变量之前。
- 在C中,间接运算符自由地站在类型和变量之间。
指针的声明方式因我阅读的文档类型而异。有些作者似乎偏爱某些变体,而其他人则使用多种变体。
- 我是否正确地假设不同变体之间没有功能上的区别?
- 如果是,那么在C语言中应该使用哪个变体的约定是什么?
在 C 语言中,声明指针有三种变体:
变体 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 *ptr;
而不是int* ptr;
,但混合使用两种风格比任何一种一致使用都要糟糕得多。
这两个之间在功能上完全没有区别:
int* ptr;
并且int *ptr;
你可以自由选择使用哪种编码风格,因为存在多种相互冲突的编码风格可供选择。
int * ptr;
也是等效的。只要星号在类型名称和变量名称之间,空格就无关紧要。 - btaint *a, *b;
与 int* a, b;
- doug65536T *a;
在Kernighan & Ritchie关于C语言的书中以及ISO/IEC 9899:2018标准中,声明指向T
的指针时,优先使用以下C风格。
T* a;
在C++中,声明指向T
的指针时,首选的方式是使用Stroustrup关于C++的书中使用的语法风格。
这两种表示法是等价的。
只有在你计划在同一行声明多个相同类型的变量时才会产生影响。例如,如果你想要多个int指针,你需要这样做:
int *a, *b, *c;
从风格上讲,当你只声明一个变量时,这是令人困惑的。很多人喜欢看到类型后面跟着变量名,并且类型应该是指向int的指针,而不是int,所以他们更喜欢:
int* a;
int* b;
int* c;
最终选择哪种形式取决于您。在我20年的C语言编程职业生涯中,我看到大约50%的人选择其中一种。
int* a, b;
,int a, *b;
和 int* a, * b;
,因为它们会分散注意力,而不是因为我不知道它们每个的含义。此外,启用所有警告进行编译并保持代码无警告有助于避免意外使用整数作为指针或反之亦然。 - Alexey Frunze就像其他人说的那样,它们的意思是相同的。但是有一个陷阱在等着你。考虑下面的代码:
int* a, b;
你可能认为这声明了两个指向int
的指针。事实并非如此。实际上,a
是int*
,但b
是int
。这是许多C程序员喜欢把*
放在变量旁而不是类型旁的原因之一。像这样书写:
int *a, b;
你不太可能被误导关于 a
和 b
是什么。
话虽如此,许多编码规范坚持声明每行不超过一个变量,即
int* a;
int b;
如果您遵循每行一个变量的规则,那么绝对不会出现混淆的情况。
C的声明是基于表达式类型而不是对象的。
如果你有一个指向名为pi
的int
指针,并想访问它所指向的整数值,你必须通过解引用指针来实现:
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]
都被称为声明符,并指定了类型说明符未给出的附加类型信息。也就是说,pc
的数组性和指针性是作为声明符的一部分指定的,而char
的性质由类型说明符给出。T *p
而不是T* p
,因为它更接近语言语法(*
是声明符的一部分),并且在声明多个项时有助于避免混淆。我见过太多的例子,人们写T* a, b;
,并期望b
是一个指针。T* p
的风格,我必须说,在某些情况下(仅限于C++),它可以使代码更易读。T
的指针:当您开始处理指向指针数组、指向数组的指针、指向函数的指针或指向指针数组的函数的指针等时,这种范例迅速崩溃。我的意思是,写类似于下面的东西:T* (*(*p)[N])(); // p is a pointer to an array of pointers to functions
// returning pointers to T.
仅仅表明了混乱的思维。虽然,如果你真的真的真的感觉必须遵循 T* p
范例,你可以创建一系列的 typedefs:
编辑
让我们再试一次:
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;
T *(*(*p)[N])();
? - jII在C语言中,除了需要分隔标记的地方外,空格并不重要。 你提供的两种变量都是语法上正确的。
变量1将指针操作符与类型关联起来,这在逻辑上是合理的。 对我来说,如果没有变量2有意义的原因,这就足够了。
变量2与C声明结构的方式一致。 在C语法中,指针操作符属于声明符(即名称),而不是类型。 这在同一声明中声明多个变量时很重要。 还有许多更为深奥的情况也很重要。
因此,对我来说,变量2更符合C语言的一致性。 但是任何一种变量都是可以辩护的,并且两种变量都是常规的。
你是正确的,编译器对于这两种方式完全一样。这两种语句都将产生(int *)
类型的变量。
至于哪种方式是正确的:这是一个引起争议的话题。如果你在公司工作或者参与开源项目,最好遵循已定义的编码风格。如果没有,则通常我会采用LNT(不留痕迹)风格,匹配这部分代码库中已经使用过的任何风格。
可以说,对于读者来说,其中一种方式更易于理解。例如:int* ptr;
将*
放得更靠近int
,更清晰地传达了我们正在谈论一个(int *)
类型...