【问题标题】:C++ style: Stroustrup' s placement of pointer asterisksC++ 风格:Stroustrup 的指针星号位置
【发布时间】:2020-05-25 01:42:20
【问题描述】:

有谁知道为什么 Stroustrup 的风格是指针的放置方式如下?具体来说,Stroustrup 就此事提供了哪些指导?

int* p;

int *p;

因为声明多个变量需要在每个变量名称旁边加上星号。这将导致:

int* p, *x;

int *p, *x;

在 K&R C 书中,他们解释说星号/指针用作助记符以帮助理解。我觉得奇怪的是指针/星号与类型相关,而不是变量,如每个示例的第二个所示。如果有关于为什么选择第一种样式的背景知识。

希望从 Stroustrup 那里得到一些引述。

我在 K&R C 第 2 版语法第 235 页中添加了星号(指针)与作为标识符的声明符相关联的位置。

回答 在这个article from Stroustrup 关于编码风格。他解释说两者都是有效的,这取决于程序员的偏好。

我不同意这是一个基于意见的问题。 Stroustrup 的文章清楚地回答了这个问题,没有意见。

【问题讨论】:

  • 我一次只声明一个变量,每个变量都在自己的行上。我也只在变量是循环索引(或 x、y 和 z)的情况下将变量命名为 1 个字母的名称,否则变量的名称通常更具描述性。如果你给你的变量一个好名字,你可能不需要写注释来描述变量的含义。
  • K&R C 中,强制在任何其他代码之前在函数顶部声明所有变量。这意味着多个变量声明很常见。在C++ 中,该限制被解除,并且一直建议不要声明变量,直到您需要使用它。因此,在需要变量之前批量声明变量一直被认为是不好的风格。 Straustrup 说,如果他不需要 C++ 来保持与 C 的向后兼容,他会更改多重声明语法,使其更加“以类型为中心”。
  • 使用int * p风格,所以每个阵营都会不喜欢;-)
  • 想知道它是否也适用于 typedef typedef int *intPtr;typedef int* intPtr;(而 using intPtr = int*;)。
  • 也许更好的问题是“为什么语言创建者定义语法以便bintint * a, b (任何间距选择),如果它与(现在) 共同理解,int * 是一个类型,a,b 是变量名”。

标签: c++ pointers coding-style conventions


【解决方案1】:

C++ 非常重视类型,当涉及到指针声明时,为了避免任何混淆,Bjarne 建议 - Stick to one pointer per declaration

来自Bjarne Stroustrup's C++ Style and Technique FAQ[强调添加]

int* p; 正确还是 int *p; 正确?

两者都是“正确的”,因为两者都是有效的 C 和 C++,并且都具有完全相同的含义。就语言定义和编译器而言,我们也可以说int*p;int * p;

int* p;int *p; 之间的选择不是关于对错,而是关于风格和重点。 C 强调表达;声明常常被认为只是一种必要的罪恶。另一方面,C++ 非常强调类型。

一个typical C programmerint *p; 并解释它*p is what is the int 强调语法,并可能指向C(和C++)声明语法来论证风格的正确性。实际上,* 绑定到语法中的名称 p

typical C++ programmerint* p; 并解释它 p is a pointer to an int 强调类型。实际上p 的类型是int*。我显然更喜欢这种强调,并认为这对于很好地使用 C++ 的更高级部分很重要。

当人们试图用一个声明声明多个指针时(仅)会出现严重的混淆:

int* p, p1; // probable error: p1 is not an int*

* 放在更靠近名称的位置并不会显着降低此类错误的可能性。

int *p, p1; // probable error?

为每个声明声明一个名称可以最大限度地减少问题 - 特别是在我们初始化变量时。人们写作的可能性要小得多:

int* p = &i; int p1 = p; // error: int initialized by int*

如果他们这样做了,编译器会抱怨。
每当某事可以通过两种方式完成时,就会有人感到困惑。每当有什么事情是口味问题时,讨论就会永远拖延下去。 每个声明坚持一个指针,始终初始化变量,混淆的根源就消失了。

有关 C 声明语法的详细讨论,请参阅 C++ 的设计和演变。

【讨论】:

  • 有趣的是,Stroustrup 没有提到这种“风格”在数组和函数中失败的事实。您不能编写 int [3] p; 来为接受 char 并返回 int 的函数声明一个包含 3 个 intint (char) p 的数组。引入一种新的声明语法是可能的,首先是对类型的完整描述,然后是要声明的标识符列表。取而代之的是,由于与语法的对比,我们有这种丑陋的杂物。
  • @EricPostpischil 你不是把不相关的事情搞混了吗?在指针声明中,int *pint* p 都是有效的,Bjarne 解释了为什么在 C++ 中 int* p 比 C 更可取。这是关于 * 的放置。在您的评论中,您提到 这种“样式”对于数组和函数来说是失败的。当然,你不能写int [3] p; 来声明一个包含 3 个int.... 的数组,因为它不符合 C++ 语言的数组声明语法。对于数组声明,标准说 .... contd..
  • (引用 c++11#8.3.4) - Arrays[dcl.array] 在声明 T D 中,D 的形式为 D1 [constant-expressionopt]attribute-specifier-seqopt[] 在 @987654359 之后@。如果允许将[] 放在D1 之前,那么这种比较可能是有意义的。
  • *pp[3] 中,*pp[3] 是与语法中的类型分开的声明符。在编写int* p 时,Stroustrop 滥用了语法中空格的灵活性,将两个未在语法中分组的标记分组。数组和函数不可能进行这种滥用,这一事实表明它是一个丑陋的组合。
【解决方案2】:

我不能代表 Bjarne,但是将星号(以及在引用的情况下的和号)与类型联系起来是有道理的,因为作为指针在语义上是变量类型的一部分。变量的名称是p,它的类型是int*。名称不是*p,类型不是int

几乎总是可以避免在单个声明中声明多个变量,所以这不是问题。

在我看来,这种方法更清晰,尤其是在返回类型的情况下:

T*
function(Args...);

T
*function(Args...);

【讨论】:

  • 如果你看语法,它不是类型的一部分。声明分为几部分,类型和声明符在不同的部分。类型为int,声明符为*p。语法先将* 绑定到p,然后再将*p 绑定到int。正如 K&R 解释的那样,int *p 给出了如何使用*p 的图片:它是一个int。所以*是表达式*p的图片的一部分。
  • @EricPostpischil 我指的是语义,而不是语法。如果你使用decltype(p),你将不会得到int。我会补充说明。
  • @EricPostpischil 我记得在阅读 K&R 第二版中的语法规则时也观察到了同样的情况。 Galik 提到 Stroustrup 的使用是因为他渴望向后兼容。真是一团糟!
  • @eerorika 我建议将关于decltype 的部分添加到您的答案中。表明这就是语言的看法意义重大。
  • @TheFloatingBrain:这与强类型与弱类型无关。语法清晰明确。
【解决方案3】:

我相信 stroustrup 的风格意味着应该避免像这样的变量声明。这似乎也是社区的普遍共识。

【讨论】:

    猜你喜欢
    • 2018-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-05
    • 2010-09-15
    相关资源
    最近更新 更多