C/C++ via Windows (1) - first thing first

来源:互联网 发布:腾讯云数据库招聘 编辑:程序博客网 时间:2024/05/22 07:47

关于这个系列

记录windows下C/C++的基础知识 - 开发环境、DLL、resource、win32 API等等。都是很基础的东西,主要是自己整理记录,顺便也许对刚接触编程的同学有些用处。


First thing first - Let's play

学东西的第一件事是什么 - 玩!

这里假定你已经在Windows下安装了Dev-cpp,为什么是这个呢?因为Dev-cpp通常包括了MinGW,而MinGW正是这个系列第2篇要介绍的C/C++开发环境。在你决定花时间去配置MinGW前,肯定要知道它好不好玩。So,Let's go

如果你之前一直使用的是Dev-cpp的图形界面,让我们来玩点别的。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

# 以下部分源自于很久之前在百度贴吧看到的一篇文章,没能找到出处。后来网上也似乎找不到此文了。我在原文基础上整理了格式,修改了几个例子,还有其他细微改动。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

设置环境变量

假设你把dev-cpp安装在C:\dev-cpp. 

设置PATH环境变量:右击"我的电脑"->属性->高级->环境变量,编辑PATH环境变量,在最后加上C:\dev-cpp\bin,记住用分号分隔。如果装有vc之类其它编译器,把它们的相关路径在PATH中删除(后面会说原因)。

    打开命令行,运行:

gcc -v 

如果出现了GCC的版本信息,那么环境变量就设置好了。

Hello World

#include<stdio.h>int main(){    printf("hello world");    return 0;}
把上面的文件保存为foo.c.。切换到文件所在的目录,编译它:

gcc  foo.c

编译成功的话,gcc会在同目录下生成一个a.exe的可执行文件。执行它:

a.exe

>hello world

可以指定生成的可执行文件名,用 -o 参数

gcc -o balabala.exe foo.c

到此,标准的C编译算是没问题了。

多文件编译

命令行的多文件编译确实让初者摸不着头脑,因为多文件他们总是用IDE的工程来做,这样相对容易,但却知其然,不知其所以然

C编译分两个阶段:编译 - 链接。编译过程将一个个.c文件变成目标文件.o/.obj,再在连接阶段生成最终可执行文件.。

所谓目标文件是指源代码与可执行文件的中间文件,它们语句上已经编译成机器码,但存在着一堆未完成的“标号”。模块1中要调用模块2中的message函数,但模块1和模块2不是同时编译,模块1中的调用者无法知道模块2中message函数的入口。连接要做的就是解决这些不同模块的调用问题。

gcc在执行编译单文件时默认是有连接动作的,而在多文件编译中,由于会调用到别的模块的函数,通常不能连接。下面做个实验:

// foo.c#include<stdio.h>// 声明用到外部函数char* message();int main(){    print("The message is: %s", message());        return 0;}

首先编译foo.c

gcc -o foo.o foo.c

出现错误:

C:\WINDOWS\TEMP/ccQsyigb.o(.text+0x2b):foo.c: undefined reference to `message' 
collect2: ld returned 1 exit status 

这个错误是“ld” - 链接器 返回的,意思是找不到message函数的入口。我们还没有编写message函数,链接器当然找不到了。注意,虽然这里我们用-o 指定输出文件名是 foo.o ,希望gcc生成未链接的目标文件,但是gcc默认是自动链接的。所以这个命令相当于告诉gcc生成一个名为 foo.o 的可执行文件。正确的做法是用 -c (c for compile)参数告诉gcc只编译不链接。

gcc -c -o foo.o foo.c

这个时候应该成功生成了foo.o这个目标文件。下一步是编写message函数:

// message.cchar* message(){    return "welcome";}
编译message.c

gcc -c -o message.o message.c

这样我们就有了foo.o 和 message.o 两个待链接的目标文件。链接它们:

gcc -o foo.exe foo.o message.o

刚才说ld才是连接器,现在却用gcc来连接……是的,当gcc发现两个文件都是目标文件时会自动调用ld。而更好的是,gcc还可能加入一些选项还控制连接过程。

什么?你就想用ld,因为那样酷!好吧骚年,这篇文章应该可以帮到你。

使用自动化工具

上面的示例中,为了编写这么一个小程序,打了不少命令行,且还附带了一堆难记的参数,的确有种然人要抛弃的感觉。还好,GNU为我们准备了一个自动化工具 - make.   make如此通用,以至于对VC6这种东西都是标配,这就是刚开始设置PATH变量时将VC相关路径去除的原因 - 防止调用到VC的make。

做个检查:

make -v

>GNU make 3.8

没错,就是它!

在刚才的实验中,,面对多条的指令,稍微懂一点DOS的人都已经想到用.bat批处理解决。老实说make的功能跟bat一样都是为了自动化,而make似乎技高一筹。先不介绍了,先写个示例编译刚才的foo程序再说:

# make file for foo.exe# 将<-tab->换成tab键foo.exe: foo.o message.o<-tab->gcc -o foo.exe foo.o message.ofoo.o: foo.c<-tab->gcc -c -o foo.o foo.cmessage.o: message.c<-tab->gcc -c -o message.o message.c

删除目录下的foo.exe, foo.o, message.o.  在命令行下输入:

make

然后这一切美妙地自动完成了,现在对这个makefile进行解释,首先make只认得叫这个名字的文件 :-(   当然如果要显式地使用某个文件作为脚本,可以用-f filename指定。

第一行是注释,任何以#开头的行都会被忽略 

下面的3个部分有些相同点,都是以下结构:

目标: 需要的文件 
<--tab-->生成目标命令 

生成文件与需要文件形成一种依赖关系,任何冒号前的名字都会成为搜寻的对像。

如上面,要先成foo.exe这个目标,需要foo.o, message.o.  make首先检查当前目录,发现没有这两个文件。于是在makefile里查找有没有生成它们的规则,有就先生成它们。然后再运行foo.exe的生成命令。当运行过一次make后,再运行,你会发现它不再工作了,因为所有的东西都是最新的。make能找到foo.exe,并且它比生成它的foo.o, message.o新。没必要再编译一次,这就是它比.bat来得聪明的原因。

make是编程工程管理的一个重要环节,学好它相当有用,这一点教程只是揭开它一小角面纱。

命令行的好处

现在你可以松一口气,回头看一看你做了些什么,你已经在命令行里做了一些非常有用的实验,可能你感觉不出它的好处,但别怕,你慢慢会体验到的。你再看看目录里的东西,是不是非常简洁?而且你知道其中每一个文件的用途。很好,一切都会在你的掌控中,而掌控这些东西看起来很过瘾……

命令行可以存在于所有的操作系统,这保证你的代码到处都可以走。而make作为有用工具常与C编译器一起销售,你不必担心自己的vc工程到了人家的borland就无法编译。

哦,对了。当你看完了makefile怎么写后,可以翻翻dev-cpp工程生成的makefile,也许会有一些启发:-)

0 0
原创粉丝点击