新说`HelloWorld`

基本上每门语言都是用"helloworld"作为她的第一讲,C语言也不例外。

传统HelloWorld


传统的教材都是让你安装一种IDE集成环境,然后照例子敲入代码,按下ctrl+r之类的运行程序,感受一下运行的结果。HelloWorld程序如下:

  • 在编辑器中敲入:
#include <stdlib.h>
#include <stdio.h>

void main() {
        printf("Hello World\n");
}
  • 按下Ctrl+r运行,当然我没有IDE环境,就用Linux终端代替一下了哈。如下:
Paste_Image.png
  • 当然这里有几个问题
    1. 当时你其实不知道这个程序是怎么被编译出来的。
    2. 当时你也不知道她在什么环境下运行的。
    3. 当时你肯定也不会去想,我这样写在其它计算机上能运行吗?
    4. 现在你肯定也没有考虑过,我能不能换个花样玩玩呢?

老生常谈


  • 为何我说一个gcc程序和一个编辑器vim程序就是c的开发环境呢?而传统的书籍,特别是国内的c程序数据,以来就让你装一个大得一逼的IDE环境,以前是vb6.0几百MB,现在是vs2015之类的好几GB。而我所说的gcc、vim充其量就几个MB。因为IDE环境集成了太多功能了,编辑、编译、调试、自动补全、语法错误提示等等。我一般不用这样环境,初学者更不应该用,她会使你太依赖IDE,不了解原理,也少了很多乐趣。
  • 其实所有程序都是编译器或者解释器读取一个纯文本中的代码,然后对要么生成目标二进制文件(编译型语言),要么直接就运行(解释型语言)了。对于C语言,当然是编译后,生成有特定格式二进制文件,在计算终端中运行,终端也是个程序,她是操作系统的一部分,操作系统也是程序(一两句话说不清这个关系>_<)。像C这样的语言,有语法解释,中间文件编译,目标程序链接这三部曲构成,当然还可以细分。语法解释主要是判断语法正确与否,然后是将#include<stdlib.h>这样的语句进行预处理生成最终的代码源文件,然后编译成与特定类型的操作系统相关的目标代码,这个目标代码其实可以在只要与当时生产的操作系统类型相同的操作系统中重复使用的,然后是链接成目标文件,这个文件大多数也可以在相同的操作系统中直接使用,但是由于有的程序会依赖特定的库,所以出表现出不能运行成功的情况罢了。比如刚才的helloworld程序在类Unix系统中,使用如下操作生成可执行文件:
Paste_Image.png

然后是运行:

Paste_Image.png

可以执行环境就是开启一个终端程序,然后./a.out运行。

  • 这段代码在绝大多数类Unix操作系统中都被编译运行,甚至这个二进制文件如果在内核相同操作系统也可以直接运行,而不需要重新编译。但是你可能注意到这个程序在编译是产生了警告,因为她的main()入口函数不是标准的,即不是可移植的。

守则一:一个负责的程序员编写程序要考虑可移植性

  • 标准的可以移植性入口函数应该是这样的:
int main(int argc, const char *argv[]) { ... }

其中的形式参数的作用就是接收运行时传入的命令参数,后面我们会讨论到。

  • 你真没想过怎么将这段代码换个花样玩?
    这个不行,作为一个程序员,脑洞太小不好,脑洞需要大开的,有多大得开多大。

换着花样玩


使用全局复用

全局变量基本是没种语言都支持的,即为全局,即是对所有人可见

  • 有一天你的老板说,现在我们生意不好,我们要改程序输出的内容,发发牢骚,而不是友好的问候。恰恰这要交给你来做,而且当时没有使用任何全局变量或着宏来代替这些输出内容,而且涉及的几十个文件可能是零零散散的分布在好几百个位置中,那么恭喜你,即使使用多文件文本替换也是挺麻烦的事,而且你总是要修改好几十个文件。如果当时使用全局变量也很好用修改的。

    1. 找一个这些文件都会引用的头文件,比如叫着utils.h,添加如下外部变量声明:
extern char g_SayHello[];
  1. 再任何一个.c文件都可以,但是推荐还是utils.c中,这个就是规范,下次,接手项目的人要修改哪个文件.h有类似上面的外部引用,自然而然的就在对应的.c中寻找其定义了:
char g_SayHello[] = "Kick the bucket!";
  1. 修改helloworld.c,其实这个名字不合适,最好加一个前缀,表面她含有入口函数,main_helloworld.c:
...
#include "utils.h"
...
int main(int argc, const char *argv[]) {
        printf("%s\n", g_SayHello);
        return EXIT_SUCCESS;
}
  1. 加入新的源文件一起编译、运行如下:
[zhoukai@zhoukai-MBPR:tmp]$ gcc main_helloworld.c utils.c
[zhoukai@zhoukai-MBPR:tmp]$ ./a.out
Kick the bucket!
[zhoukai@zhoukai-MBPR:tmp]$

使用宏复用

宏是c语言强有力的特性之一,不使用宏,你会做很多不讨喜的工作,但是滥用宏也会不讨喜,所有任何东西都有利有弊。就像没有坏人,就体现不出好人;没有细菌这样的微生物,满世界都是尸体一样。这个是一个哲学问题〜〜〜

  • 继续上面的情景。你好不容易完成了需求,结果你老板说,我们需要在不同操作系统上让运行程序发不同的牢骚〜〜〜,虽然你心中有一万匹草泥马在狂奔,但为了工资忍了吧。显然上面的代码在不同的计算机上发布时,如果在编译后需要让程序运行时显现一些不同的东西,是需要修改源代码的,很不方便,做这样的事情,宏的优点就体现出来了,因为在编译时,可以给定参数定义一个宏让源代码相同的程序有不同的行为:
    1. 还是utils.h,添加如下宏:
//稍作解释,下面的宏定义是关联预编译条件宏使用,即如果没有定义宏,则定一个默认的宏
#ifndef SAY_HELLO
#define SAY_HELLO "Kick the bucket!"
#endif
  1. 修改main_helloworld.c:
int main(int argc, const char *argv[]) {
        printf("%s\n", SAY_HELLO);
        return EXIT_SUCCESS;
}
  1. 编译不同的行为的程序:
[zhoukai@zhoukai-MBPR:tmp]$ gcc main_helloworld.c utils.c -DSAY_HELLO=\"Drop\ dead\!\" -o a.out
[zhoukai@zhoukai-MBPR:tmp]$ gcc main_helloworld.c utils.c -DSAY_HELLO=\"Go\ to\ hell\!\" -o ab.out
[zhoukai@zhoukai-MBPR:tmp]$ gcc main_helloworld.c utils.c -DSAY_HELLO=\"Damn\ you\!\" -o abc.out
[zhoukai@zhoukai-MBPR:tmp]$ ./a.out
Drop dead!
[zhoukai@zhoukai-MBPR:tmp]$ ./ab.out
Go to hell!
[zhoukai@zhoukai-MBPR:tmp]$ ./abc.out
Damn you!
[zhoukai@zhoukai-MBPR:tmp]$

稍作解释,gcc最简单的使用就是gcc <源文件名>,然后就会生成默认的程序文件a.out,但是一般都希望又一个自定义的程序文件名,所以加上选项参数-o <目标名>;在不加-c <源文件名>的情况下都是直接完成三部曲,生成可执行文件的;其它还有很多可选的参数,后面慢慢说。

  • 可以看到不同的程序使用同样的源代码编译的,但是编译时可以重定义宏,从而改变其行为。这里使用了可选参数-Dmacro="string"(加上''只是因为shell环境需要转义双引号),这样可以将编译时宏参数带入预处理,从而替换默认的宏参数。

结束语


为什么要写这么多,其实也不是高深的代码。目的就是一个,你在编写代码的时候是否比别人多想了一步呢?是否考虑过代码的可移植性呢?是否考虑过代码的可复用性呢?是否考虑过代码的可维护性呢?这些!都是一名合格的程序员应该考虑的问题。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容