C中有指针声明的约定吗?

在C中声明指针时,有2个(编辑:3)变体:

变式A:
int* ptr;

变式B:
int *ptr;

变式C:
int * ptr;

  • 在A中,间接运算符已附加到该类型。
  • 在B中,间接运算符已预先添加到变量中。
  • 在C中,间接运算符在类型和变量之间自由站立。

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

  • 我是否正确地假设不同变体之间的function没有区别?
  • 如果是,是否存在一个变量应该在C中使用的约定?

两者之间的function完全没有区别

 int* ptr; 

 int *ptr; 

您使用的是由您自己决定的,有多种冲突的编码风格可供选择。

其他人没有提到过的是

 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。

如果你正在与项目中的其他程序员合作,你应该遵循编码标准中的任何现有约定,或者如果没有,那么代码已经被编写。 我个人更喜欢int *ptr; to int* ptr; ,但使用两种风格的混合比使用任何一种风格要差得多。

只有当您计划在同一行上声明多个相同类型的变量时才重要。 例如,如果需要多个int指针,则需要执行以下操作:

 int *a, *b, *c; 

但是在风格上,当你只声明一个变量时,这会令人困惑。 许多人喜欢看到类型后跟变量名,类型应该是int的指针,而不是int,所以他们更喜欢:

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

无论你喜欢一种forms而不是另一种forms,最终取决于你。 在专业编程C的20年中,我看到大约50%的人选择一个而不是另一个。

它们的意思与其他人所说的相同。 虽然有一个陷阱等着你。 考虑以下代码:

 int* a, b; 

你可能会认为这是指向int指针。 不然,不然。 实际上aint*但是bint 。 这是许多C程序员更喜欢将*放在变量旁边而不是类型的原因之一。 这样写的时候:

 int *a, b; 

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

说了这么多,许多编码标准都坚持要求每行声明不超过一个变量,即e。

 int* a; int b; 

如果你遵循每行规则的一个变量,那么肯定没有混淆的余地。

 T *a; 

是Kernighan&Ritchie关于C的书中使用的指向T的指针的首选C风格方式。

 T* a; 

是Stroustrup关于C ++的书中使用的声明T指针的首选C ++风格方式。

两种符号都是等价的。

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]都称为声明符,并指定类型说明符未给出的其他类型信息。 IOW, pc的array-ness和pointer-ness被指定为声明符的一部分,而char -ness由类型说明符指定。

至于风格适当的问题 ……

两者都不是“正确的”,但我(以及许多其他C程序员)更倾向于编写T *p而不是T* p ,因为它更接近地反映了语言语法( *是声明者的一部分)并且它有助于避免声明多个项目时的混淆。 我看过很多人写T* a, b;例子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将指针运算符与类型相关联,这足够合乎逻辑。 对我来说,如果没有Variant 2的理由,那就足够了。

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

因此,对我来说,变体2与C更加一致。但是这两种变体都是可防御的,并且两种变体都是传统的。

你是对的,对编译器来说都是完全相同的。 两个语句都将生成一个类型为(int *)的变量。

至于哪个是正确的:可以蠕虫! 这通常是一个辩论主题。 如果您在公司或OSS工作,最好按照定义的编码风格。 如果没有一个,我通常会使用LNT(不留任何痕迹)匹配样式,无论在代码库的这一部分中使用了什么样的风格。

可以说,对于读者来说,一个人更容易理解。 例如int* ptr; 使*更接近int ,更清楚地传达我们正在谈论的(int *)类型…