首页 文章

为什么C语法如此复杂? [关闭]

提问于
浏览
27

我是编程的新手,虽然我已经教自己Python大约一年了,我不久前学过C# .

本月我在大学开设了C程序设计课程,我只想问一下; “为什么C代码如此复杂?”

写“你好世界” . 在Python中就像“打印'Hello world . '”一样简单,但在C中它是:

# include <iostream>
using namespace std;

int main ()
{
    cout << "Hello world.";
    return 0;
}

我知道这可能是一个很好的理由但是,为什么......

  • ...你每次都要包含<iostream>吗?你有没有需要它?

  • ...标准库的相同问题,何时不需要std :: *?

  • ... "main"是一个函数?你有没有打电话给主要功能?为什么是整数?为什么C需要一个main函数但Python不需要?

  • ......你需要"std::cout << "吗?与Python相比,这不是那么长而复杂吗?

  • ...即使你永远不会使用它,你还需要返回0吗?

这可能是因为我正在学习这样的基本C,但到目前为止我所做的每个程序都是这样的,所以我必须一遍又一遍地重新输入相同的代码 . 这不是多余的吗?编译器本身无法输入此代码,因为它总是相同的(即afaik总是包含<iostream>,std,int main,return 0)

10 回答

  • 76

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

    对于您的个人问题:

    • 你每次都要包括 <iostream> 吗?你有没有需要它?

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

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

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

    我会在这里注意到,使用指令( using namespace )经常在C代码中不受欢迎,因为它们导入了很多名称并且可能导致名称冲突 . 尽可能使用using-declarations( using std::cout; ),因为它限制了using指令的范围(例如,限制为一个函数或一个源文件) . 没有充分理由不要将 using namespace 放在 Headers 中 .

    • 是"main"的一个功能部分?你有没有打电话给主要功能?为什么是整数?为什么C需要一个main函数但Python不需要?

    main 是程序的入口点 - 执行开始的地方 . 在Python中, __main__ 模块用于相同的目的 . C不像Python那样执行定义函数之外的代码,因此它的入口点是函数而不是模块 .

    • 你需要"std::cout << "吗?与Python相比,这不是那么长而复杂吗?

    只有在未通过using-directive( using namespace std; )或using-declaration( using std::cout )将 cout 名称导入全局名称空间时,才需要 std::cout . 在这方面,它再一次像Python的 import stdfrom std import *from std import cout 之间的区别 .

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

    • 即使你永远不会使用它,你还需要返回0吗?

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

  • 6

    在帖子结尾回答你的问题时,可以用C的哲学概括:

    你不支付你不使用的东西 .

    你并不总是需要使用stdin或stdout(Windows / GUI应用程序?),也不总是使用STL,你写的所有东西都不一定使用标准main(winAPI)等 . 如前一张海报所说,C比Python低 . 您将接触到更多细节, offers you more control over what you're doing.

  • 5

    ...你必须每次都包括在内吗?你有没有需要它?

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

    转过来的问题:在python中你需要在大多数非平凡的程序中导入sys和/或os . 为什么?

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

    您可以使用使用行,也可以使用std ::前缀 . 这非常类似于python的选择,你可以说“来自sys import *”或“import sys”,然后不得不用“sys . ”作为前缀 . 在python中你必须说“sys.stdout” . “std :: cout”真的更糟吗?

    ...是一个功能的“主要”部分?你有没有打电话给主要功能?为什么是整数?为什么C需要一个main函数但Python不需要?

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

    Python没有相同的约定,因为使用Python,您可以在不在函数中的模块中使用代码 . 加载模块时会执行此代码 . 有趣的是,许多人认为将代码放在模块的顶层并且通过执行以下操作来创建主函数是不好的方式:

    def main(argv):
      # program goes here
    
      return 0
    
    if __name__ == '__main__':
      sys.exit(main(sys.argv))
    

    此外,在Python中,您告诉解释器模块在运行时是“主”模块 . 例如:“python foo.py” . 在C中,“main”模块(有效地)是具有称为main的函数的模块 . (如果有多个带有main函数的模块,那就是链接器错误 . )

    ...你需要“std :: cout <<”吗?与Python相比,这不是那么长而复杂吗?

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

    也就是说,许多人确实认为使用IO的位移操作符的iostreams惯例是一个坏主意 . 具有讽刺意味的是,Python似乎受到了这种语法的“启发” . 如果你想使用print写入stdout以外的地方你可以说:

    print >>file, "Hello"
    

    ...即使你永远不会使用它,你还需要返回0吗?

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

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

  • 9

    Python是 high-level 语言 . C是 middle-level 语言 .

  • 2

    C之所以相当复杂,其原因之一是因为它旨在解决大型程序中出现的问题 . 在C创建AT&T时,他们最大的C程序大约有1000万行代码 . 在这种规模下,C不能很好地发挥作用 . C解决了这类程序遇到的许多问题 .

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

    • 你会 include <iostream> 它有_1018282_已经有10.000个C文件,很少见的是小于1000,有时小于100会产生用户可见的输出 .

    • print "Hello, world" 这样的语句假设有一个默认输出,但很难一概而论 . cout << "Hello, world" 表单使输出显式出现,但同样的表单也允许 cerr << "Goodbye, world"MyTmpFile << "Starting phase #" << i

    • 标准库位于 std:: 命名空间中 . 我的10.000个文件将在另外25个名称空间中 .

    • main 在很多方面都是一个奇怪的东西,作为启动功能 .

  • 6

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

    ...你每次都要包括<iostream>吗?你有没有需要它?

    <iostream> 是iostreams的头文件之一,是负责输入/输出的C标准库的一部分;在这种情况下,您需要它才能访问 std::cout . 如果你需要包含它 - 例如,大多数包含类定义的文件可能不需要 <iostream> .

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

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

    您可以使用 using 语句将来自另一个命名空间的项目放入当前范围,有关示例,请参阅this FAQ entry(并解释为什么盲目地将 std 全部放入范围内的原因!) .

    ...为什么“主要”部分是一个功能?你有没有打电话给主要功能?为什么是整数?为什么C需要一个main函数但Python不需要?

    C中的可执行语句必须包含在函数中, main 函数定义为执行开始的位置 . 在Python中,可执行语句可以放在文件的顶层,并定义执行 .

    如果您愿意,可以拨打 main() - 这通常不是理由 . 在幕后,大多数C的实现都会在运行时库中完成一些启动内务管理后为您调用 main() .

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

    ...为什么你需要“std :: cout <<”?与Python相比,这不是那么长而复杂吗?

    这只是一个设计差异 . iostreams是一个相当复杂的野兽,具有许多功能,其中一个副作用是语法对于简单的任务有时有点难看 .

    ...即使您永远不会使用它,为什么还需要返回0?

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

  • 7

    这让我想起了The Evolution of a Programmer . 现在展示的一些语言和技术有点陈旧,但你应该得到一般的想法 . :)

  • 3

    如果要将内容输出到控制台,请包含 <iostream> . 由于打印"Hello world"涉及控制台输出,因此需要 iostream .

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

    如果你想要C风格,你总是可以使用 printf("hello world"); 而不是 std::cout << "hello world"; . 编写它会更快,并允许您进行格式化输出 .

    return 0 来自 main 表示程序已成功执行 .

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

  • 0

    博德之门:

    你并不总是需要 <iostream> . 您唯一需要的是:

    • main 函数(或 WinMain ,如果您正在编写Win32应用程序) .

    • 变量,函数,运算符,语言结构( ifwhile 等) .

    • 能够将库中的功能包含到您的程序中 .

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

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

    1当您编写"communicate"与其他程序的程序时,这很有用 . 程序能够正确执行的最简单方法是使用错误代码 .

  • 5

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

    换句话说,你抱怨的事情是你的样板 . 但它们是重要的细节,与该语言的其他用户不同 .

相关问题