在C语言中,指针声明是否有惯例?

28

在 C 语言中,声明指针有三种变体:

变体 A:

int* ptr;

变体B:

int *ptr;

变体C:

int * ptr;
  • 在A中,间接运算符已追加到类型之后。
  • 在B中,间接运算符已前置于变量之前。
  • 在C中,间接运算符自由地站在类型和变量之间。

指针的声明方式因我阅读的文档类型而异。有些作者似乎偏爱某些变体,而其他人则使用多种变体。

  • 我是否正确地假设不同变体之间没有功能上的区别?
  • 如果是,那么在C语言中应该使用哪个变体的约定是什么?

12
我不知道为什么有人要投票关闭这个问题。在我看来,它似乎是一个合理的问题,但我从1980年以来一直在编写C程序。 - Peter Rowell
3
我不得不和 @AlexeyFrunze 意见不同(5年后我知道了)。我曾尝试通过谷歌搜索(或者说 DuckDuckGo)来寻找差异,但只有从另一个问题的链接才找到了这个。 - Ungeheuer
3
我刚刚投票支持重新开放。语法问题相当简单(在这种情况下,编译器不关心空格),但涉及规范的问题更有趣(正如我在我的答案中所讨论的那样)。 - Keith Thompson
2
@AlexeyFrunze:这是我使用谷歌搜索引擎后找到这个网站的过程。当人们使用谷歌搜索时,通常意味着他们正在寻找其他人提出类似问题并得到答案的情况。但在其他人可以通过谷歌找到答案之前,必须有人先问所有“琐碎”的问题。 :-) - Matt
显示剩余2条评论
8个回答

21

没有人提到的一个问题是:

int *ptr;

与语言语法更加接近。

  • int *ptr;是一个声明,由以下部分组成:
    • 声明说明符int,后跟
    • 声明符*ptr

(实际上这里省略了一些步骤,但基本思想已经表达出来了。)

由于声明遵循使用的顺序,这意味着*ptr的类型为int。由此可以得出ptr的类型为int*

有人可能会认为这比...更好。

int* ptr;

出于同样的原因

x = y+z;

更好。
x=y + z;

当然你 可以

int* ptr;

并将其理解为“ptrint* 类型”。许多程序员都会这样做,并且能够很好地处理这种情况(在C++中,这往往是首选的方式)。编译器不在乎你采用哪种方式,而且任何阅读你的代码的人都不应该有理解上的困难。

但无论你选择哪种间隔方式,你都需要理解 int *ptr; 真正的含义,这样当你看到

int *ptr, i;

如果你不可避免地需要阅读别人的代码,你会立刻了解到ptr是一个指针,i是一个整数。

如果你在和其他程序员一起开发项目,你应该遵循编码标准中已有的约定,或者如果没有,那就按照代码已经写好的方式来。我个人更喜欢使用int *ptr;而不是int* ptr;,但混合使用两种风格比任何一种一致使用都要糟糕得多。


15

这两个之间在功能上完全没有区别:

int* ptr;
并且
int *ptr;

你可以自由选择使用哪种编码风格,因为存在多种相互冲突的编码风格可供选择。


1
+1。就SO而言,这是正确的答案。没有区别,选择权在你手中。 - Dan Fego
如果你想要更加技术化,使用 int * ptr; 也是等效的。只要星号在类型名称和变量名称之间,空格就无关紧要。 - bta
@DanFego:就编译器而言,这是正确的答案。使用一种形式或另一种形式都有合法的理由,并且SO是讨论这些理由的完全好地方。 - Keith Thompson
4
答案未解决源头误解,即 * 与变量名相关,而 * 不与类型名称相关。请考虑: int *a, *b;int* a, b; - doug65536

15
T *a;

在Kernighan & Ritchie关于C语言的书中以及ISO/IEC 9899:2018标准中,声明指向T的指针时,优先使用以下C风格。

T* a;

在C++中,声明指向T的指针时,首选的方式是使用Stroustrup关于C++的书中使用的语法风格。

这两种表示法是等价的。


4
+1 表示对权威性的呼吁的赞同。;-) - R.. GitHub STOP HELPING ICE

13

只有在你计划在同一行声明多个相同类型的变量时才会产生影响。例如,如果你想要多个int指针,你需要这样做:

int *a, *b, *c;

从风格上讲,当你只声明一个变量时,这是令人困惑的。很多人喜欢看到类型后面跟着变量名,并且类型应该是指向int的指针,而不是int,所以他们更喜欢:

int* a;
int* b;
int* c;

最终选择哪种形式取决于您。在我20年的C语言编程职业生涯中,我看到大约50%的人选择其中一种。


1
这(上面的两个变体)是处理笨拙的星号关联规则的非常清晰的方式。我避免编写 int* a, b;int a, *b;int* a, * b;,因为它们会分散注意力,而不是因为我不知道它们每个的含义。此外,启用所有警告进行编译并保持代码无警告有助于避免意外使用整数作为指针或反之亦然。 - Alexey Frunze
@user1118321,感谢您发布了少数实际解决问题的答案之一:在同一行上声明多个变量。我严格反对将*与类型放在一起,因为这表明开发人员实际上并不理解语法。 - doug65536

13

就像其他人说的那样,它们的意思是相同的。但是有一个陷阱在等着你。考虑下面的代码:

int* a, b;

你可能认为这声明了两个指向int的指针。事实并非如此。实际上,aint*,但bint。这是许多C程序员喜欢把*放在变量旁而不是类型旁的原因之一。像这样书写:

int *a, b;

你不太可能被误导关于 ab 是什么。

话虽如此,许多编码规范坚持声明每行不超过一个变量,即

int* a;
int b;

如果您遵循每行一个变量的规则,那么绝对不会出现混淆的情况。


4

C的声明是基于表达式类型而不是对象的。

如果你有一个指向名为piint指针,并想访问它所指向的整数值,你必须通过解引用指针来实现:

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的性质由类型说明符给出。
至于哪种风格是正确的问题...
两种方式都不是“正确”的,但我(以及许多其他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 范例,你可以创建一系列的 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

1

在C语言中,除了需要分隔标记的地方外,空格并不重要。 你提供的两种变量都是语法上正确的。

变量1将指针操作符与类型关联起来,这在逻辑上是合理的。 对我来说,如果没有变量2有意义的原因,这就足够了。

变量2与C声明结构的方式一致。 在C语法中,指针操作符属于声明符(即名称),而不是类型。 这在同一声明中声明多个变量时很重要。 还有许多更为深奥的情况也很重要。

因此,对我来说,变量2更符合C语言的一致性。 但是任何一种变量都是可以辩护的,并且两种变量都是常规的。


0

你是正确的,编译器对于这两种方式完全一样。这两种语句都将产生(int *)类型的变量。

至于哪种方式是正确的:这是一个引起争议的话题。如果你在公司工作或者参与开源项目,最好遵循已定义的编码风格。如果没有,则通常我会采用LNT(不留痕迹)风格,匹配这部分代码库中已经使用过的任何风格。

可以说,对于读者来说,其中一种方式更易于理解。例如:int* ptr;*放得更靠近int,更清晰地传达了我们正在谈论一个(int *)类型...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接