为啥 C++ 语法如此复杂? [关闭]

Posted

技术标签:

【中文标题】为啥 C++ 语法如此复杂? [关闭]【英文标题】:Why is the C++ syntax so complicated? [closed]为什么 C++ 语法如此复杂? [关闭] 【发布时间】:2009-08-31 04:37:26 【问题描述】:

我是编程新手,虽然我已经自学了大约一年的 Python,而且我前段时间学习了 C#。

这个月我在大学开始了 C++ 编程课程,我只需要问一下; “C++代码为什么这么复杂?”

写“Hello world”。在 Python 中就像“print 'Hello world.'”一样简单,但在 C++ 中是:

# include <iostream>
using namespace std;

int main ()

    cout << "Hello world.";
    return 0;

我知道这一切可能是有充分理由的,但是,为什么...

... 每次都必须包含 吗?你曾经需要它吗? ...对于标准库的同样问题,什么时候不需要 std::*? ...“主要”部分是函数吗?你有没有调用过 main 函数?为什么是整数?为什么 C++ 需要有 main 函数,而 Python 不需要? ...你需要“std::cout ...即使您永远不会使用它,您是否需要返回 0?

这可能是因为我正在学习如此基本的 C++,但到目前为止我制作的每个程序看起来都是这样的,所以我必须一遍又一遍地重新输入相同的代码。这不是多余的吗?编译器不能自己输入这段代码,因为它总是一样的(即afaik你总是包含,std,int main,return 0)

【问题讨论】:

简单回答:C++ 和 Python 旨在解决具有不同约束的不同问题。不同的设计目标为您带来不同的设计。 我不确定标签“冗余代码”在这种情况下是什么意思。 main() 在大多数重要用途中的任务不仅仅是输出到控制台。它是程序执行的入口点。返回0;是给操作系统的哪个启动程序,哪个可能使用返回值作为程序执行的状态报告。您可能希望先阅读 Stroustrup 博士的常见问题解答,然后再将 C++ 归咎于语法 @research.att.com/~bs/bs_faq.html 之外的许多其他内容。 有些程序不需要&lt;iostream&gt;。相信我,当你看到它们时,你会想念这些只包含&lt;iostream&gt; 的简单程序。 这就是为什么程序员应该首先学习低级语言,这样他们才能理解高级语言为他们做了什么。 @Eduardo Leon:当我还是一名初级程序员时,我会强烈反对你。现在我是一名计算机科学专业的毕业生并在行业工作了 2 年,我强烈同意。只涉足高级语言是无法获得低级理解的。 【参考方案1】:

C++ 是一种更底层的语言,可以在没有解释器上下文的情况下执行。因此,它与 Python 相比有许多不同的设计选择,因为 C++ 没有可以依赖的环境来管理类型和内存等信息。 C++ 可用于编写操作系统内核,其中除了程序本身之外没有任何代码在机器上运行,这意味着该语言(某些库设施不适用于所谓的独立实现)必须是自包含的。这就是为什么 C++ 没有与 Python 的eval 等效的原因,也没有确定类成员等的方法,也没有其他需要执行环境的特性(或者程序本身的大量开销而不是这样的环境)

针对您的个人问题:

是否每次都必须包含&lt;iostream&gt;?你曾经不需要它吗?

#include &lt;iostream&gt; 是将&lt;iostream&gt; 标头导入程序的指令。 &lt;iostream&gt; 包含标准输入/输出对象 - 特别是 cout。如果您不使用标准 I/O 对象(例如,您只使用文件 I/O,或者您的程序使用 GUI 库,或者正在编写操作系统内核),则不需要&lt;iostream&gt;

标准库的同样问题,什么时候不需要std::*?

std 是包含所有标准库的命名空间。 using namespace std; 有点像from std import *,而#include 指令(在这方面)更像是一个准系统import std 语句。 (实际上,机制是相当不同的,因为 C++ 不使用using namespace std; 自动查找std 中的对象; using 指令仅将名称导入全局命名空间。)

我要在这里指出,使用指令 (using namespace) 在 C++ 代码中经常不受欢迎,因为它们会导入大量名称并可能导致名称冲突。在可能的情况下,最好使用 using 声明 (using std::cout;),因为它限制了 using 指令的范围(例如,仅限于一个函数或一个源文件)。永远不要在没有正当理由的情况下将using namespace 放在标题中。

“主要”部分是函数吗?你有没有调用过 main 函数?为什么是整数?为什么 C++ 需要有 main 函数,而 Python 不需要?

main 是程序的入口点——执行开始的地方。在 Python 中,__main__ 模块具有相同的用途。 C++ 不像 Python 那样在定义的函数之外执行代码,所以它的入口点是一个函数而不是一个模块。

你需要“std::cout

std::cout 仅在您不通过使用指令 (using namespace std;) 或使用声明 (using std::cout) 将 cout 名称导入全局命名空间时才需要。在这方面,又很像Python的import stdfrom std import *from std import cout之间的区别。

&lt;&lt; 是标准流对象的重载运算符。 cout &lt;&lt; value 调用cout 的函数输出value。 Python 不需要这样的额外代码,因为print 是内置在语言中的;这对 C++ 没有意义,因为 C++ 甚至可能没有操作系统,更不用说 I/O 库了。

即使您永远不会使用它,是否也需要返回 0?

没有。 main(没有其他功能)最后有一个隐含的return 0;main 的返回值(或者,如果调用 exit 函数,则传递给它的值)作为退出代码传递回操作系统。 0 表示程序执行成功——它没有遇到错误等。如果遇到错误,应该返回一个非零值(或传递给exit)。

【讨论】:

哇!非常感谢您如此详细的回复! 没问题 :) 我自己其实只是在学习 Python,所以能够反过来解释是对我知识的一个很好的测试。 也许我做错了。你认为继续使用 C++ 几个月,直到我打下相当扎实的基础,然后尝试学习像汇编这样的低级语言是个好主意吗?像 Python 这样的高级语言应该是你最后学习的语言吗? 我认为自上而下开始不一定有什么问题。对于一个新程序员来说,学习汇编是令人沮丧的,因为做最简单的事情需要付出很多努力(这就是为什么它是一种学习编码的有效方法的部分原因)。您甚至不需要像了解计算机体系结构那样了解汇编。我推荐一本像 /Programming Language Pragmatics/ 这样的书,它解释了计算机是如何工作的,因此可以让你更好地理解所有语言。但只要你保持开放的心态(比如问这个问题而不是咆哮)你会做得很好 “C++ 不会像 Python 那样执行定义函数之外的代码”——静态变量的初始化可以执行代码【参考方案2】:

在文末回答你的问题,可以用C++的哲学来概括:

不用为不用的东西付费。

你并不总是需要使用标准输入或标准输出(Windows/GUI 应用程序?),你也不会总是使用 STL,你编写的所有东西也不一定使用标准的 main (winAPI) 等。作为以前的海报说,C++ 比 Python 低。您将接触到更多细节,这让您可以更好地控制自己正在做的事情。

【讨论】:

【参考方案3】:

...你必须包括 每次?你有没有 需要吗?

如果您不打算在该模块中使用 iostreams,则不需要它。在较大的程序中,很少有模块直接进行任何实际的 IO,因此很少需要真正使用 iostream。

扭转问题:在 python 中,您需要在大多数非平凡程序中导入 sys 和/或 os。为什么?

...标准的相同问题 库,什么时候不需要 std::*?

您可以使用 using 行,也可以使用 std:: 前缀。这与 python 给你的选择非常相似,要么说“from sys import *”,要么说“import sys”,然后必须在前面加上“sys.”。在 python 中,你必须说“sys.stdout”。 “std::cout”真的更糟吗?

...“主要”部分是函数吗?做 你曾经调用过主函数吗?为什么 它是一个整数吗?为什么 C++ 需要 有一个主要功能,但 Python 没有?

是的,main 是一个函数。通常你不会自己打电话给 main 。名称“main”是为程序的入口点保留的。它返回一个整数,因为返回的值用作程序的状态代码。在 Python 中,如果要返回非零状态码,可以使用 sys.exit。

Python 没有相同的约定,因为使用 Python,您可以在模块中而不是函数中包含代码。此代码在您加载模块时执行。有趣的是,许多人认为在模块的顶层编写代码是一种不好的风格,而是通过执行以下操作来创建一个 main 函数:

def main(argv):
  # program goes here

  return 0

if __name__ == '__main__':
  sys.exit(main(sys.argv))

另外,在 Python 中,当您运行它时,您会告诉带有模块的解释器是“主”模块。例如:“python foo.py”。在 C 语言中,“main”模块(实际上)是具有称为 main 的函数的模块。 (如果有多个模块有一个主函数,那就是链接器错误。)

...你需要“std::cout

Python 中的等价物实际上是“sys.stdout.write(...)”。 Python 的 print 语句是一种特殊情况的简写。

话虽如此,许多人确实认为 iostreams 对 IO 使用位移运算符的约定是一个坏主意。具有讽刺意味的是,Python 似乎受到了这种语法的“启发”。如果您想使用 print 写入 stdout 以外的其他地方,您可以说:

print >>file, "Hello"

... 你是否需要返回 0 即使 你永远不会使用它?

您不会使用它,但您的程序会。如前所述,您返回的值是您程序的状态码。

旁白:我确实觉得 C++ 过于复杂,但不是因为你提到的任何一点。一旦您开始编写具有多个模块并且不仅仅是写入标准输出的重要程序,您提到的所有差异都会消失(从某种意义上说,您在 Python 中需要同样多的复杂性)。

【讨论】:

【参考方案4】:

当您想将内容输出到控制台时,您可以包含&lt;iostream&gt;。由于打印“Hello world”涉及控制台输出,所以需要iostream

main 函数基本上是由操作系统调用的。它使用传递给程序的命令行参数调用。它返回一个整数,因为程序必须向操作系统返回一个错误代码(这是确定最后一个命令是否成功的标准方法)。

如果你想使用 C 风格,你总是可以使用 printf("hello world"); 而不是 std::cout &lt;&lt; "hello world";。它的编写速度更快,并且可以进行格式化输出。

你从mainreturn 0表示程序执行成功。

编译器不会自动包含所有标准库并使用命名空间std,因为有时您的代码和您可能根本不需要的库代码之间会发生名称冲突。您并不总是需要所有的库。同样,有时您正在使用不同的主程序(Windows 开发想到了它自己的不同的WinMain 启动函数)。编译器也不会自动return 0,因为有时程序需要指示它未成功完成。

【讨论】:

不管怎样,在纯 C 中,程序可以像调用操作系统一样调用main() 函数,尽管这在 C++ 中是被禁止的。这样做的唯一真正目的是生成每个人都喜欢的错误。 实际上,编译器放入的存根调用main() 函数,但本质上,是操作系统开始执行,它必须以某种方式从某个地方开始。 这是一个很好的答案,我只知道如果我下意识地认为我正在做的事情毫无意义,我将无法跟上 C++ 的步伐。从响应来看,似乎 not 使用 std 和 iostream 是例外。为什么不设法表明用户没有使用 std 或 iostream,而不是表明用户正在使用它们呢?而且我知道 Python 是一门高级语言,就像 Aziz 指出的那样(虽然我不太确定区别),但是 Python 怎么能设法拥有如此简单而优美的语法,它与复杂的 C++ 做同样的事情一个? 我猜这是因为 C++ 很大程度上继承了 C,一种较旧的低级语言。程序员期望 C/C++ 进行大量控制,其中一部分包括明确告诉编译器要包含哪些头文件以及要使用哪些命名空间。 Python 和脚本语言更隐含一些,为了便于开发和维护而牺牲了一些控制。【参考方案5】:

所有这些事情都有充分的理由。 C++ 是一种非常广泛的语言,它用于从小型嵌入式系统到由数百名程序员构建的大型应用程序。一个人构建一个在桌面上运行的小程序的用例绝不是唯一的。所以有时你正在构建库组件。在这种情况下,没有 main()。有时你在一个没有标准库的小系统上工作。在那种情况下,没有标准。有时您想构建一个与其他 Unix 文本工具一起使用的 Unix 工具,并使用从 main() 返回的 int 来指示其完成状态。

换句话说,您抱怨的事情对您来说都是样板。但对于该语言的其他用户来说,它们是至关重要的细节。

【讨论】:

【参考方案6】:

这让我想起了The Evolution of a Programmer。所展示的一些语言和技术现在有点过时了,但您应该了解总体思路。 :)

【讨论】:

【参考方案7】:

C++ 相当复杂的原因之一是它旨在解决大型程序中出现的问题。在 C++ 创建为 AT&T 时,他们最大的 C 程序大约有 1000 万行代码。在那个规模上,C 不能很好地运行。 C++ 解决了您在使用此类程序时遇到的许多问题。

话虽如此,也可以回答原来的问题:

您可以在需要的地方include &lt;iostream&gt;。如果您有 10.000 个 C++ 文件,通常少于 1000 个,有时少于 100 个会产生用户可见的输出。 像print "Hello, world" 这样的语句假定存在默认输出,但很难概括。 cout &lt;&lt; "Hello, world" 形式明确了输出的去向,但同样的形式也允许 cerr &lt;&lt; "Goodbye, world"MyTmpFile &lt;&lt; "Starting phase #" &lt;&lt; i 标准库位于std:: 命名空间中。我的 10.000 个文件将位于另外 25 个命名空间中。 main 在很多方面都很奇怪,它是启动功能。

【讨论】:

【参考方案8】:

博德:

您并不总是需要&lt;iostream&gt;。您将永远需要的唯一东西是:

    main 函数(或 WinMain,如果您正在编写 Win32 应用程序)。 变量、函数、运算符、语言结构(ifwhile 等)。 能够将库中的功能包含到您的程序中。

其他一切都是特定于应用程序的。

正如其他发帖者所说,main 函数的返回值是错误代码1。如果main 返回 0,请高兴:一切正常!

1这在您编写与其他程序“通信”的程序时很有用。一个程序可以“告诉”另一个程序是否正确执行的最简单方法是使用错误代码。

【讨论】:

【参考方案9】:

正如人们所说,简单的答案是它们是不同的语言,具有不同的目标。回答您的具体问题...

...您每次都必须包含&lt;iostream&gt; 吗?你从来不需要它吗?

&lt;iostream&gt;是iostreams的头文件之一,是C++标准库中负责输入/输出的部分;在这种情况下,您需要它来访问std::cout。如果您不在源文件中执行 I/O 操作,则不需要包含它 - 例如,大多数包含类定义的文件可能不需要 &lt;iostream&gt;

...对于标准库同样的问题,什么时候不需要 std::*?

std 是标准库中包含类的命名空间的名称;它的存在是为了避免名称冲突。 Python 有包和模块可以做到这一点。

您可以使用using 语句将来自另一个命名空间的项目带入您当前的作用域,请参阅this FAQ entry 示例(并解释为什么盲目地将所有std 带入作用域是不好的!)。

...为什么“主要”部分是函数?你有没有调用过 main 函数?为什么是整数?为什么 C++ 需要有 main 函数,而 Python 不需要?

C++ 中的可执行语句必须包含在函数中,而main 函数被定义为执行开始的地方。在 Python 中,可执行语句可以放在文件的顶层,执行被定义为 .

如果您愿意,您可以致电main()——毕竟它只是一个函数——但通常没有理由这样做。在后台,一旦运行时库完成了一些启动内务管理,大多数 C++ 实现都会为您调用 main()

main() 的返回值返回给操作系统。这源于 C 和 UNIX,其中应用程序需要提供一个 1 字节的退出状态代码,并且从 main() 返回该值是一种明确的表达方式。

...为什么需要“std::cout

这只是设计差异。 iostreams 是一个相当复杂的野兽,有很多特性,它的副作用之一是语法有时对于简单的任务来说有点难看。

...为什么即使你永远不会使用它也需要返回 0?

你确实使用它;这是作为程序退出状态返回给操作系统的值。

【讨论】:

【参考方案10】:

Python 是高级语言。 C++ 是中级语言。

【讨论】:

不,您并不总是需要 iostream。许多图形/窗口应用程序不会打扰控制台输出。

以上是关于为啥 C++ 语法如此复杂? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Visual C++ 2010 使用此汇编语法进行内存寻址?

为啥这么多汇编语法都包含逗号? [关闭]

为啥我从 tensorflow 网站收到此代码的语法错误? [关闭]

为啥语言在语法上不更严格? [关闭]

在 C++ 中使用默认参数跳过模板参数真的不可能吗,为啥语法建议不这样?

为啥正则表达式如此有争议? [关闭]