.cs是什么文件_C/C++|头文件、源文件分开写的源起及作用

1 C/C++ 编译模式

通常,在一个 C++ 程序中,只包含两类文件—— .cpp 文件和 .h 文件。其中,.cpp 文件被称作 C++ 源文件,里面放的都是 C++ 的源代码;而 .h 文件则被称作 C++ 头文件,里面放的也是 C++ 的源代码。

C++ 语言支持“分别编译”(separatecompilation)。也就是说,一个程序所有的内容,可以分成不同的部分分别放在不同的 .cpp 文件里。.cpp 文件里的东西都是相对独立的,在编译(compile)时不需要与其他文件互通,只需要在编译成目标文件后再与其他的目标文件做一次链接(link)就行了。比如,在文件 a.cpp 中定义了一个全局函数 "void a(){}",而在文件 b.cpp 中需要调用这个函数。即使这样,文件 a.cpp 和文件 b.cpp 并不需要相互知道对方的存在,而是可以分别地对它们进行编译,编译成目标文件之后再链接,整个程序就可以运行了。

这是怎么实现的呢?从写程序的角度来讲,很简单。在文件 b.cpp 中,在调用 "void a()" 函数之前,先声明一下这个函数 "void a();",就可以了。这是因为编译器在编译 b.cpp 的时候会生成一个符号表(symbol table),像 "void a()" 这样的看不到定义的符号,就会被存放在这个表中。再进行链接的时候,编译器就会在别的目标文件(实现文件)中去寻找这个符号的定义。一旦找到了,程序也就可以顺利地生成了,如果找不到,则会产生链接错误。

注意这里提到了两个概念,一个是"定义",一个是"声明"。简单地说,"定义"就是把一个符号完完整整地描述出来:它是变量还是函数,返回什么类型,需要什么参数等等。而"声明"则只是声明这个符号的存在,即告诉编译器,这个符号是在其他文件中定义的,我这里先用着,你链接的时候再到别的地方去找找看它到底是什么吧。定义的时候要按 C++ 语法完整地定义一个符号(变量或者函数),而声明的时候就只需要写出这个符号的原型了。需要注意的是,一个符号,在整个程序中可以被声明多次,但却要且仅要被定义一次。试想,如果一个符号出现了两种不同的定义,编译器该听谁的?

这种机制给 C++ 程序员们带来了很多好处,同时也引出了一种编写程序的方法。考虑一下,如果有一个很常用的函数 "void f() {}",在整个程序中的许多 .cpp 文件中都会被调用,那么,我们就只需要在一个文件中定义这个函数,而在其他的文件中声明这个函数就可以了。

2 为什么C++要分为头文件和源文件?

这是否和外部调用有关?为什么现在大多数语言都没有采用这种设计?为什么调用dll有时需要使用Windows提供的API导出函数或者结构,而不能直接include xxxx.h或者像C#写的dll那样在项目中添加引用然后直接using xxxx。

需要从C/C++历史演变的角度回答下这个问题。

上世纪70年代初,C语言初始版本被设计出来时,是没有头文件的。这一点与后世的Java只有.java文件,C#只有.cs文件很相似。即使是现代的C编译器,头文件也不是必须的。我使用下面这个例子说明:

//alpha.cint main(){    print_hello();}//beta.cvoid print_hello(){    puts("hello");}

上例只有两个源文件,alpha.c与beta.c。其中alpha.c使用了一个自定义函数print_hello,beta.c中使用了标准库函数puts。注意:alpha.c与beta.c都没有包含任何头文件。

你可以使用MSCL编译器来编译:

cl/Fe:program.exealpha.cbeta.c

或者GCC以及Clang:

clang-oprogramalpha.cbeta.c

这样会得到一个名为program的可执行文件,并且它可以正常工作。

以beta.c为例:当beta.c被编译时,编译器解析到名为puts的符号,虽然它是未定义的,但从语法上可以判断puts是一个函数,故而将其认定为函数,作为外部符号等待链接就可以了(倘若alpha,beta是C++源文件,

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值