WBl*_*sko 177 c variables pointers naming-conventions
为什么大多数C程序员都将变量命名为:
int *myVariable;
Run Code Online (Sandbox Code Playgroud)
而不是像这样:
int* myVariable;
Run Code Online (Sandbox Code Playgroud)
两者都有效.在我看来,星号是类型的一部分,而不是变量名称的一部分.谁能解释这个逻辑?
lui*_*bal 235
它们完全等同.但是,在
int *myVariable, myVariable2;
Run Code Online (Sandbox Code Playgroud)
很明显,myVariable的类型为int*,而myVariable2的类型为int.在
int* myVariable, myVariable2;
Run Code Online (Sandbox Code Playgroud)
似乎很明显两者都是int*类型,但是因为intmyVariable2类型不正确.
因此,第一种编程风格更直观.
bio*_*inc 115
如果你以另一种方式看待它,那*myVariable就是类型int,这是有道理的.
ojr*_*rac 40
因为*更接近变量而不是类型:
int* varA, varB; // This is misleading
Run Code Online (Sandbox Code Playgroud)
然而,即使是最好的单行声明对我来说也是违反直觉的,因为*是该类型的一部分.我喜欢这样做:
int* varA;
int varB;
Run Code Online (Sandbox Code Playgroud)
像往常一样,代码越紧凑,可读性越强.;)
Mec*_*cki 32
到目前为止,没有人在这里提到的是这个星号实际上是C中的" 取消引用运算符 ".
*a = 10;
Run Code Online (Sandbox Code Playgroud)
该线之上并不意味着我要分配10到a,这意味着我要分配10到任何内存位置a点.我从未见过有人在写作
* a = 10;
Run Code Online (Sandbox Code Playgroud)
你呢?因此,取消引用运算符几乎总是在没有空格的情况下编写.这可能是为了将它与跨越多行的乘法区分开来:
x = a * b * c * d
* e * f * g;
Run Code Online (Sandbox Code Playgroud)
这*e会误导,不是吗?
好的,现在以下行实际意味着什么:
int *a;
Run Code Online (Sandbox Code Playgroud)
大多数人会说:
这意味着它a是一个指向int值的指针.
这在技术上是正确的,大多数人喜欢以这种方式查看/阅读它,这就是现代C标准定义它的方式(注意语言C本身早于所有ANSI和ISO标准).但这不是看待它的唯一方式.您还可以按如下方式阅读此行:
取消引用的值a是类型int.
所以事实上,这个声明中的星号也可以看作是一个解引用运算符,它也解释了它的位置.这a是一个指针根本没有真正声明,它隐含的事实是,你唯一可以解除引用的是指针.
C标准仅为*运营商定义了两个含义:
间接只是一个单一的含义,没有额外的意义来声明指针,只有间接,这是取消引用操作所做的,它执行间接访问,因此在这样的语句中int *a;也是间接访问(*均值)间接访问)因此上面的第二个陈述比第一个陈述更接近标准.
Inj*_*ilo 17
我将在这里说明这个问题的答案是直接的,无论是变量声明还是参数和返回类型,都应该是星号旁边的名字:int *myVariable;.要了解原因,请查看如何在C中声明其他类型的符号:
int my_function(int arg); 一个功能;
float my_array[3] 对于一个数组.
一般模式,称为声明跟随使用,是符号的类型被分割成名称前面的部分,以及名称周围的部分,名称周围的这些部分模仿您将用于获取的名称左侧类型的值:
int a_return_value = my_function(729);
float an_element = my_array[2];
并且:int copy_of_value = *myVariable;.
C++在引用中抛出了一个扳手,因为在使用引用时的语法与值类型的语法相同,所以你可以说C++对C采用不同的方法.另一方面,C++保留相同的在指针的情况下C的行为,所以在这方面引用确实是奇怪的.
mac*_*die 11
这只是一个偏好问题.
当您阅读代码时,在第二种情况下区分变量和指针会更容易,但是当您将一个常见类型的变量和指针放在一行中时可能会导致混淆(本身通常不鼓励项目指南,因为降低了可读性).
我更喜欢用类型名称旁边的相应符号声明指针,例如
int* pMyPointer;
Run Code Online (Sandbox Code Playgroud)
一位伟大的大师曾经说过"你必须按照编译器的方式阅读它."
http://www.drdobbs.com/conversationsa-midsummer-nights-madness/184403835
当然这是关于const放置的主题,但同样的规则适用于此.
编译器将其读取为:
int (*a);
Run Code Online (Sandbox Code Playgroud)
不是:
(int*) a;
Run Code Online (Sandbox Code Playgroud)
如果您养成将星形放在变量旁边的习惯,它将使您的声明更容易阅读.它还避免了眼睛,如:
int* a[10];
Run Code Online (Sandbox Code Playgroud)
喜欢的int* x;人试图强迫他们的代码进入一个虚构的世界,其中类型在左侧,标识符(名称)在右侧。
我说“虚构”是因为:
在 C 和 C++ 中,在一般情况下,声明的标识符被类型信息包围。
这听起来可能很疯狂,但你知道这是真的。这里有些例子:
int main(int argc, char *argv[])意思是“main是一个函数,它接受一个int和一个指向char并返回一个的指针数组int。” 换句话说,大部分类型信息都在右侧。有些人认为函数声明不算数,因为它们在某种程度上是“特殊的”。好的,让我们尝试一个变量。
void (*fn)(int)meanfn是一个指向函数的指针,该函数接受 anint并且不返回任何内容。
int a[10]将 'a' 声明为一个 10int秒的数组。
pixel bitmap[height][width].
显然,我已经精心挑选了在右边有很多类型信息的例子来表达我的观点。有很多声明,其中大多数(如果不是全部)类型都在左侧,例如struct { int x; int y; } center.
这种声明语法源于 K&R 希望让声明反映用法的愿望。阅读简单的声明是直观的,阅读更复杂的声明可以通过学习右-左-右规则(有时称为螺旋规则或仅称为右-左规则)来掌握。
C 非常简单,以至于许多 C 程序员都采用这种风格并将简单的声明编写为int *p.
在 C++ 中,语法变得稍微复杂一些(包括类、引用、模板、枚举类),并且作为对这种复杂性的反应,您会看到在许多声明中将类型与标识符分开的努力更多。换句话说,int* p如果您查看大量 C++ 代码,您可能会看到更多的-style 声明。
在任何一种语言,你可以总是有左边的类型变量的声明(1)从来没有定义多个变量在同一语句,和(2)利用typedefS(或别名声明,这些声明,讽刺的是,把别名类型左侧的标识符)。例如:
typedef int array_of_10_ints[10];
array_of_10_ints a;
Run Code Online (Sandbox Code Playgroud)
本主题中的许多论点都是主观的,关于“星号绑定到变量名”的论点是幼稚的。以下是一些不仅仅是意见的论点:
被遗忘的指针类型限定符
从形式上讲,“星”既不属于类型也不属于变量名,它是其自身名为pointer的语法项的一部分。正式的 C 语法 (ISO 9899:2018) 是:
(6.7) 声明:
声明说明符 init-declarator-list opt;
其中声明说明符包含类型(和存储),而init-declarator-list包含指针和变量名称。如果我们进一步剖析这个声明符列表语法,我们就会看到:
(6.7.6)声明符:
指针选择直接声明 符
...
(6.7.6)指针:
*类型限定符列表选择
*类型限定符列表选择 指针
声明符是整个声明,直接声明符是标识符(变量名),指针是星号,后跟属于指针本身的可选类型限定符列表。
是什么让关于“星属于变量”的各种风格争论不一致的,是他们忘记了这些指针类型限定符。int* const x,int *const x或int*const x?
考虑一下int *const a, b;,a和的类型是b什么?不再那么明显“明星属于变量”了。相反,人们会开始思考const属于哪里。
您绝对可以提出一个合理的论点,即星形属于指针类型限定符,但仅此而已。
指针的类型限定符列表可能会给使用该int *a样式的人带来问题。那些在 a 中使用指针typedef(我们不应该这样做,非常糟糕的做法!)并认为“星星属于变量名”的人倾向于编写这个非常微妙的错误:
/*** bad code, don't do this ***/
typedef int *bad_idea_t;
...
void func (const bad_idea_t *foo);
Run Code Online (Sandbox Code Playgroud)
这编译干净。现在您可能认为代码是 const 正确的。不是这样!这段代码意外地是伪造的 const 正确性。
的类型foo实际上是int*const*- 最外面的指针被设为只读,而不是指向的数据。所以在这个函数中我们可以做**foo = n;,它会改变调用者中的变量值。
这是因为在表达式中const bad_idea_t *foo,*不属于这里的变量名!在伪代码中,这个参数声明被读作const (bad_idea_t *) foo而不是读作(const bad_idea_t) *foo。在这种情况下,星形属于隐藏指针类型 - 类型是指针,常量限定指针写为*const。
但是上例中问题的根源在于将指针隐藏在 a 后面typedef而不是*样式的做法。
关于在一行上声明多个变量
在一行中声明多个变量被广泛认为是不好的做法1)。CERT-C 很好地总结为:
DCL04-C。每个声明不要声明多个变量
刚读英语,然后常识同意一个声明应该是一个声明。
变量是否是指针并不重要。在一行中声明每个变量可以使代码在几乎所有情况下都更加清晰。
所以关于程序员混淆的争论int* a, b是不好的。问题的根源在于使用了多个声明符,而不是*. 不管风格如何,你都应该这样写:
int* a; // or int *a
int b;
Run Code Online (Sandbox Code Playgroud)
另一个合理但主观的论点是,给定int* a的类型a是毫无疑问的int*,因此星形属于类型限定符。
但基本上我的结论是,这里发布的许多论点都只是主观和幼稚的。你不能真正为任何一种风格做出有效的论证——这确实是一个主观的个人偏好问题。
1) CERT-C DCL04-C。
| 归档时间: |
|
| 查看次数: |
50485 次 |
| 最近记录: |