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;
并将其读作“ ptr
是int*
类型”。 而且很多程序员都是这样做的,并且相处得很好(它往往是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
指针。 不然,不然。 实际上a
是int*
但是b
是int
。 这是许多C程序员更喜欢将*
放在变量旁边而不是类型的原因之一。 这样写的时候:
int *a, b;
你不太可能被误导为a
和b
是什么。
说了这么多,许多编码标准都坚持要求每行声明不超过一个变量,即e。
int* a; int b;
如果你遵循每行规则的一个变量,那么肯定没有混淆的余地。
T *a;
是Kernighan&Ritchie关于C的书中使用的指向T
的指针的首选C风格方式。
T* a;
是Stroustrup关于C ++的书中使用的声明T
指针的首选C ++风格方式。
两种符号都是等价的。
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]
都称为声明符,并指定类型说明符未给出的其他类型信息。 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 *)
类型…