【问题标题】:Why is it thought of 'T *name' to be the C way and 'T* name' to be the C++ way?为什么认为 'T *name' 是 C 方式,而 'T* name' 是 C++ 方式?
【发布时间】:2011-09-20 22:56:33
【问题描述】:

注意:这个问题是关于星号 (*) 的位置。

在我看到的大多数 C 代码中(例如,在Beej's guide to network programming 中),所有变量声明/定义都使用T *name 格式,即将* 绑定到变量名。指针被认为属于变量,而不是类型。

在我看到的大多数 C++ 代码中,格式为T* name,即,它将* 绑定到变量的类型。指针被认为属于类型,而不是变量。我自己,作为一个纯 C++ 编码器,也使用这种格式,作为一个 pointer-to-type 显然(对我来说)属于类型,而不是变量。 (顺便说一句,即使是 C++ 标准在示例中也使用这种格式。:))

这有(历史)原因吗?当程序员开始做 C++ 时,思维方式是否发生了变化?

如果 C 编码器(使用前一种格式)能够解释他/她为什么使用它而不是后者,那也很好。

【问题讨论】:

  • 出于好奇,你如何写“指向函数返回T”的指针?只是问问。
  • 我认为 int *a, *bint* a, b 是一些人更喜欢前者的原因
  • @Nemo:std::identity<T (*)()>::type pf;。 :P 当然typedef T (*pf_type)(); pf_type pf;,但这只是因为解析规则。
  • @Anycorn:我不认同这个论点——没有人像你的第二个例子那样编写代码。这与“总是在 IF 语句中添加大括号,因为我们假设下一个人太愚蠢而无法添加它们”的论点一样糟糕。
  • @billy 我很困惑为什么你告诉 Anycorn 他的观点不是问题,而你的回答与他的观点完全相同!

标签: c++ c pointers history conventions


【解决方案1】:

如果我冒险猜测,我会说这是因为 C++ 人更有可能认为类型信息本身就是一个东西,因为模板可以在编译时以编程方式操作类型。它们也不太可能在同一个声明中声明多个变量。

T* 样式将类型信息集中在一个位置并使其脱颖而出,如果您从未在同样的说法。

就我个人而言,我发现T* 风格非常令人讨厌并且非常不喜欢它。 * 是类型信息的一部分,这是真的,但是编译器解析它的方式使它实际上附加到名称,而不是类型。我认为T* 方式掩盖了正在发生的重要事情。

在我的观察中,我似乎在 C++ 社区中是一个稀有的人。我注意到你对最受欢迎的风格有同样的看法。

当然,要明确的是,任何一种风格都适用于任何一种语言。但我确实注意到你做的同样的事情,一种风格在 C 代码中更常见,而另一种风格在 C++ 中更常见。

【讨论】:

  • +1 T* 确实打算限定 type 而不是 variable。为了避免T* foo, bar; 的混淆,我分别声明它们。
  • 如果您认为代码在星号位置上“令人讨厌”,那么我认为您担心的是错误的事情。
  • 在同一行声明多个变量会使代码更难阅读,无论它们是否是指针。不要这样做:您真的不必像 70 年代那样保存保存源代码的 HD 空间。如果这是人们将 * 放在变量名旁边的唯一原因,那真是太糟糕了。
  • 使用模板时,类型变得更加重要。 MyClass<T>MyClass<T*> 完全不同。
  • "* 是类型信息的一部分,这是真的,但是编译器解析它的方式使它实际上附加到名称,而不是类型。我认为 T* 方式掩盖了一些重要的东西正在发生。”您无需担心编译器。编译器会好的。 Optimise your code style for humans, not for the compiler。不过,我 +1 是一个很好的答案,它很好地涵盖了 实际 问题的核心(尽管您的简短与个人观点相切:P)
【解决方案2】:

在 K&R 中,他们使用 type *name 表示法,所以这可能是许多 C 程序员得到它的地方。

【讨论】:

    【解决方案3】:

    就我个人而言,我不同意这一点——我认为没有 C 或 C++ 方法可以做到这一点。我从未见过任何证据表明这一点。但是,我确实有一个假设,为什么带有星号的语法更接近 C 中声明的变量名。

    在 C 中(至少在 C89 中,绝大多数 C 都在使用),您必须在块的顶部声明所有变量。这导致程序员做

    T a, b, c;
    

    相对经常,而在 C++ 中这种情况很少见。 (在 C++ 中,您声明变量的位置接近它们的使用位置,并且变量通常具有构造函数参数等;因此很少在一行中声明多个对象)

    这也恰好是语法很重要的唯一情况,因为语句

    T* a, b, c;
    

    声明一个指针,而不是程序员可能期望的三个。

    由于在 C 语言中在一行中放置多个声明更为常见,而且星号的位置也很重要,因此程序员更有可能将星号与变量相关联。

    也就是说,我从未见过任何证据——这只是猜测。

    【讨论】:

    • 根据经验,我发现 C 和 C++ 源代码之间存在明显差异。例如,我从未在 C 代码中见过T* var。而且我读过的大部分 C++ 都使用T* var 风格而不是T *var
    • @Cicada:我在两种语言中都看到了很多。
    【解决方案4】:

    我不认为你对你的区别是正确的,

    T * 样式中有 C++ code

    code 样式中有 C code

    我认为这只是项目参与者的个人喜好问题。

    【讨论】:

    • 我明确写了“大多数”而不是“全部”。此外,显然,我只能对我目前看到的代码这么说。 :P
    • 是的,但是如果您查看代码量,而不是用这种风格编写,您可能会得出结论,most 可能是您的个人印象,而不是事实。
    【解决方案5】:

    只是为了引发一些争议:

    • C++ 用户通常声明每行一个声明可以将星号放在类型上(左侧)。 int* a; int* b;
    • C 和 C++ 都使用附加到名称(右侧)的星号进行解析。 int *a;
    • C++ 预处理器通常将星号移到左侧。 C 预处理器将其移动到右侧。
    • 在任何一种语言中,将其放在左侧对于在同一语句中声明多个相同类型的变量会显得很奇怪。 int* a, * b, * c;
    • 有些句法元素在左边看起来很愚蠢。 int* (* func)()

    还有其他C的元素用错了,比如const,也属于右边! int const a;。这通常放在类型的左侧,尽管属于类型在其左侧。必须修改许多编译器来处理这种用法。在 C++ 中,您可以观察到这符合常量方法,因为如果将其放在左侧,编译器将无法为您推断:int A::a() const。这也与constrestricted 的嵌套使用以及具有int const * 等声明的朋友一起打破。 const 的常规用法表明这是一个指向整数的常量指针,但实际上是 int *const

    tl;博士

    你们一直都做错了,把一切都放在正确的位置。

    【讨论】:

    • "int const *. 常规用法表明这是一个指向整数的常量指针" 什么废话。它看起来不像英语或任何其他人类语言,所以在不知道这个声明的含义的情况下,你为什么会假设它是一个指向整数的常量指针?正确的 RTL 读数同样合乎逻辑。
    • @Tomalak Geret'kal:我想我们在这里争论的是同一件事。除了常规用法我指的是 C 用法,而不是英语。
    • @Tomalak Geret'kal:仅供参考,我不知道 C 是否真的是 RTL,但螺旋规则具有明确的牵引力:c-faq.com/decl/spiral.anderson.html
    【解决方案6】:

    C 声明遵循与表达式相同的规则(例如优先级)。事实上,考虑这样的声明是完全有效的

    int *foo;
    

    将表达式*foo 的类型(即应用于foo 的间接运算符)声明为int 而不是foo 类型为int*

    但是 - 正如其他人已经指出的 - 在 C++ 中,通常将类型视为单独的,并且 - 由于模板 - 可修改实体,因此使用类似声明是有意义的

    int* foo;
    

    【讨论】:

      【解决方案7】:

      C 程序员倾向于使用一种风格而 C++ 程序员使用另一种风格的原因很简单:Kernighan & Ritchie 在their book 中使用了“C 风格”,而 Stroustrup 在his book 中使用了“C++ 风格” .

      【讨论】:

      • 这个。此外,Stroustrup 还特别描述了一个更像 C,而另一个则更像 C++,以及为什么他这么认为,here
      【解决方案8】:

      因为 Bjarne 获得了后见之明的好处:他意识到 C 声明符语法是“一个失败的实验”(阅读:C 声明符语法被延迟)。其余的已经被其他人回答了。

      【讨论】:

      • @Tomalak: 当然,向后兼容:(
      • 如果函数中的auto name -> type 可以捕捉到变量,那就太好了,我猜它会变得不那么丑陋并且更容易解析。
      • @FredOverflow 但是引用没有向后兼容性要求,但 C++ 复制了指针语法。 =(
      【解决方案9】:

      有几个人提到了非常好的观点。我只想指出,虽然 C 非常强烈地保留了“声明反映使用”的含义,但 C++ 没有。 C++ 中的一些声明符不反映在声明中的使用;

      int &ref; // but "&ref" has type "int*", not "int".
      int &&ref; // but "&&ref" is not valid at all.
      

      我不认为 C++ 程序员写它不同实际上有这个原因,但这可能是阻止 C++ 书籍作者提及它的东西,这可能会影响那些 C++ 程序员。

      【讨论】:

      • &&ref 在 C++11 中无效吗?
      【解决方案10】:

      来自Stroustrup's C++ Style and Technique FAQ

      一个“典型的 C 程序员”写int *p; 并解释它“*p 是什么int”强调语法,并可能指向 C(和 C++)声明语法来争论风格。实际上,* 绑定到语法中的名称 p

      “典型的 C++ 程序员”会写 int* p; 并解释说“p 是指向 int 的指针”,强调类型。实际上p 的类型是int*。我显然更喜欢这种强调,并认为它对于很好地使用 C++ 的更高级部分很重要。

      【讨论】:

      • 我同意这是一个比我的答案稍微好一点的答案,尽管它说的大致相同,但表达的观点偏见更加微妙(但至少这是名人的观点偏见,我猜以某种方式计数)。但我会说,当我写下我的答案时,我并不知道 Stroustrup 的这句话。所以很有趣,我们都说了基本相同的话。
      • 我喜欢这个答案,因为你不会试图用你自己的观点来证明它的合理性。相反,您会向在该主题上或多或少具有权威性的人提出上诉。
      猜你喜欢
      • 2020-09-19
      • 2012-07-07
      • 2017-08-17
      • 2011-05-12
      • 2012-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-10
      相关资源
      最近更新 更多