《C程序设计新思维》一1.7 通过本地文档来编译C程序

本节书摘来自异步社区《C程序设计新思维》一书中的第1章,第1.7节,作者 【美】Ben Klemens,更多章节内容可以访问云栖社区“异步社区”公众号查看

1.7 通过本地文档来编译C程序

到此,你应该已经看出编译过程的套路了。

1. 设定一个表述编译器选项的变量。

2. 设定一个表述连接器选项的变量,包括为你用的所有库配置的-l选项。

3. 用make命令或者你的IDE的操作来把这些变量转换为完整的编译和连接命令。

本章的余下部分将把以上步骤做最后一次,并采取一种非常简短的设置:仅仅用shell。如果你思维敏捷,可以通过摘录一些语句段落到解析器上来学习脚本,你也将可以同样地把C代码贴在你的命令行上。
**
1.7.1 在命令行里包含头文件**
gcc和Clang有一个用于包含头文件的方便的配置。例如:


f84511900663933692c793b8156d1c216a48f1a4

这和在C源文件的开头放入下面这行等价的:


4b4a3953bf8ed698c064b665becf3df022907dcf

同样地也可以用clang –include stdio.h。

通过把以上加入我们的编译器调用,最终我们可以把hello.c程序写成只有一行:


5af1b0b2fd171c77042353f8b162c2e1387220ec

通过以下方式顺利编译:


6b85038f1ac60562e30f51f707d4abd0c6e920ed

或者利用shell命令:


cae1d9cbd648dcc6eecae91ec384c83d6e03928d

这个关于-include的窍门是随编译器不同的,并且把信息从代码转移到编译指令中。如果你认为这是一个坏习惯,那好,就忘了它吧。
**
1.7.2 统一的头文件**
很久以前,编译器处理一个哪怕不算复杂的程序要也要花费好几秒甚至几分钟的时间,所以减少一些编译器不得不做的工作,可以产生一些显而易见的好处。我现在的stdio.h和stdlib.h每个都有1,000多行(可以用wc –l /usr/include/stdlib.h验证),time.h也有400行,这就意味着下面这个仅7行的小程序,实际上是一个大约2,400行的程序:


eb1cf4c14162bd74303f8b700a0262a5e92d7986

而今,编译器已经不再以为2,400行是一个大问题,这种编译也就花费不到1秒。那么我们为何还要花时间去为一个特定的程序挑选正确的头文件呢?

如果你是一个gcc或Clang用户,当你拥有一个统一的头文件后,你就不必再书写甚至只有一行#include 的类似代码,因为你可以在CFLAGS中用-include allheads.h来代替它,然后不用再担心与项目无关的头文件了。


eac2698fb7e10bf3e7209a94d7c999043d5c281f

自己动手:为自己写一个通用的头文件,让我们称之为allheads.h,然后把你用过的所有头文件都扔到里面去,那么它就将看起来像:


2fc5e5f6b004fe053d8a05c437fc72b346bb2cd8

我其实无法告诉你它确切长得什么样,因为我不知道你每天都用什么文件。

现在你有了这个集成的头文件,只需在所有文件的开头加上这么一句:


7dbeb9d016f0a7077f3cd44ad8fe777e5a8ee420

.这样你就不用再操心头文件了。的确,加上这个头文件会扩展出10,000行额外的代码,而且其中大多数和手头的程序无关。但是你不会留意到,而且没用的声明也不会改变最终的可执行文件。
头文件还可以起到限定作用域的目的,但是这个通常在你写函数和结构时更重要,而不是对于那些库。作用域限定范围的目的不是为了缩小命名空间以防止计算机过热;而是为了减少作为程序员的你的认知负担。我猜你甚至都不熟悉你所使用的库中的大部分的函数,如果你都不了解,那么它们也不可能带来任何认知负担。其他的语言甚至不做区分并有成堆的关键词,比如R项目,就有752个启动时内部定义的关键词。

1.7.3 嵌入文档
嵌入文档是POSIX标准的shell的一个特性,你可以用在C、Python、Perl,或者别的什么中,他们也使得这本书更加有用和有趣。并且,如果你想要有一个多语言的脚本,嵌入文档是一个实现的方便法门。在Perl中做解析,在C语言中做算数,然后用Gnuplot产生漂亮的图片,并且集成在一个文本文件里。

这是一个Python的例子。通常,你通过下面的方法告诉Python去运行一个脚本:


659147600896338a92149c86947843bdd2ec89d3

你可以使用‘-’以使用stdin作为输入文件:


a2fa36f986728f4c812baf4ce53d5c6307e79704

这里要用'-'而不仅仅是-,表明这是一个纯文本,而不是一个用来引出类似python–c “print ‘Hi’”中的c的开关。许多程序遵从GNU的习惯,使用两个横线来表示停止读取开关并把随后的输入读取为纯文本。因此:


7bd239eb7bc981a939b8057a14ac8d742d4ac114

也会起作用,但是这类事情会吓到大家。
理论上,你应该通过echo把一些过长的脚本放到命令行上,但是你很快就会看到有很多短小、不符合期望的解析在进行——比如,你可能需要用”hi”而不是”hi”。

那么,嵌入文档实际上根本就不会被解析。比如:


d52b62850267b5e6fd436933d654c090e6d55fb4

嵌入文档是一项标准的shell特性,所以它们应该在任何POSIX系统中都可以用。
“XXXX”代表你想用的任何字符串;“EOF”也很流行,而“-----”只要你把连字符的数量和顶部和底部都配合得很好的话,看起来也还不错。当shell看到你选定的字符串单独占一行,它会停止向stdin输出脚本。这就是一般脚本解析的过程。
还有以<<-开始的变体。这种变体去掉了所有的每行开头的tab键,所以你可以把一个渐次缩进的shell脚本文档放在这里,而不会打短缩进的流程。当然,这对Python的嵌入文档而言是一个灾难。
作为另一个变体,<<”XXXX”和<1.7.4 从stdin中编译
现在,回到C的世界中来:我们可以用嵌入文档来编译通过gcc或Clang贴到命令行的C代码,或者在一个多语言的脚本中的几行程序。

我们不再用makefile,所以我们需要一个单行的编译命令。为了让生活变得不那么痛苦,让我们给它起个别名。把它输出到你的命令行,或者把它添加在你的.bashrc、.zshrc,或者任何适合的地方:


3fa1c53ce73de5d29c0e47a2c0f88b9b599e8323

这里的allheads.h是你之前放在一起的集成的头文件。当你写C代码的时候,用-include选项是你最不应该考虑的事情,并且我也发现当C代码中出现#的时候,bash的历史变得有点靠不住。

在编译行,你将认出 '-' 意味着用stdin而不是从一个命名的文件输入。-xc认为这是C代码,因为gcc代表GNU编译器组合,而不是GNU C编译器,也没有类似.c的输入文件名来提示它,我们必须指明这不是Java、Fortran、Objective C、Ada,或者C++(对Clang也一样,即使它的名字是有意在提示是C语言)。无论你在makefile中对LDLIBS和CFLAGS做了多少客制化,这里也要做。现在你已经扬帆出海了,可以在命令行中编译C代码了:


bb5262d0519c2e6b15dda41e4846c781c6f49a02

我们可以使用嵌入文档来粘贴简短的C程序到命令行,并写一点带有争议性的测试程序。不仅是你不需要一个makefile,你甚至也不需要一个输入文件。

不要认为这种事情就是你的基本工作状态。但是剪切粘贴代码段落到命令行是有趣的,并且在一个较长的shell脚本内可以用一步完成C也是非常棒的。

[1]  GUI——图形用户界面,如目前常见的Windows、iOS等操作系统。——译者注

[2]  Cygwin有Red Hat, Inc.运营的项目,该公司也允许用户购买不按照GPL版权发布自己源代码的权利。

[3] 虽然Msys、MinGW和一些其他作为包提供,这些包的数量与典型的包管理器提供的上百个包相比显得很苍白。值得注意的是,预编译的库并不是点击一下或者输入一个命令行就可以被安装好的。不过,当你读到这些的时候,我的抱怨可能已经被解除了,也就是说有了更多的MinGW包可用。

[4] 借用最新出现的grunge rock风格,指代最新的C编译器——译者注

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值