开始你的编程之旅
开始你的编程之旅
编译程序
在Visual Studio中,编译、执行都是一个按键的事情,好像VS一个软件完成了所有的工作(实际上也不是)。但在Linux里,每个工作都有专门的软件来完成。编译程序我们用最常见的gcc/g++
来完成。
gcc main.c -o main
然后用ls命令看一下:
$ ls
main main.c
注意
强调一下,这里的$
是提示符,不要输入。我会在只有命令时去掉$
;而内容同时包含命令和回显时加入$
。
可以输出了main
这个文件,这里要注意的是,linux并不需要后缀名来标识某个文件是可执行文件。你应该可以看到这个文件是绿色的,这是ls
命令用颜色帮我们标识出的文件的类型。
运行一下。
$ ./main
Hello World!
这里要注意的是你需要加路径运行,.
表示当前路径,./main
表示当前路径下的main
文件。Linux可执行文件不会在当前路径下搜索。所以如果你直接main
,会执行失败。
还有一点要注意的是表示路径的分隔符,Linux使用/
,Windows使用\
,方向不同。
如果.是当前路径,那..是什么呢?
如果你用ll
命令来显示当前路径文件的详细信息,你除了看到.
之外,还可以看到一个..
路径:
total 48
drwxr-xr-x 1 leon leon 4096 Oct 29 20:35 ./
drwxr-xr-x 1 root root 4096 Oct 29 13:16 ../
-rw------- 1 leon leon 744 Oct 29 16:40 .bash_history
-rw-r--r-- 1 leon leon 220 Oct 29 13:16 .bash_logout
-rw-r--r-- 1 leon leon 3771 Oct 29 13:16 .bashrc
-rw-r--r-- 1 leon leon 0 Oct 29 13:26 .hushlogin
drwxr-xr-x 1 leon leon 4096 Oct 29 13:17 .landscape/
-rw-r--r-- 1 leon leon 0 Oct 29 13:17 .motd_shown
-rw-r--r-- 1 leon leon 807 Oct 29 13:16 .profile
-rw-r--r-- 1 leon leon 0 Oct 29 16:15 .sudo_as_admin_successful
-rw------- 1 leon leon 9054 Oct 29 20:35 .viminfo
-rw-r--r-- 1 leon leon 20 Oct 29 19:36 .vimrc
-rwxr-xr-x 1 leon leon 16696 Oct 29 20:35 main*
-rw-r--r-- 1 leon leon 72 Oct 29 20:35 main.c
既然.
是当前路径,那么..
是什么呢?
你可以自己试试,用cd ..
看进入这个路径会如何。
cd
用来在不同的目录中切换,这个命令和Windows环境下的命令是一样的。
你可以试试用这个命令在Linux的文件系统里漫游,其中/
表示根目录,如果你要回到你的home
目录下继续工作,可以cd ~
。
makefile
你可能会觉得每次要执行代码,都要从vim里退出,然后再编译和执行是很麻烦的事。没错,但我们有办法来解决他。
对于Linux系统来说,早期进行项目组织的方式是用makefile。我们先看看makefile怎么写:
规则
vim makefile
输入内容:
build:
gcc main.c -o main
你可以把makefile看作一系列规则的描述,例如上面的这个makefile里,指明build
这条规则应该执行的命令是gcc main.c -o main
。
注意命令这行需要以\t
(也就是tab
键)开始,这是makefile的格式要求。
退出,在命令行下键入:
$ make
gcc main.c -o main
你可以看到这条指令被执行了。
make这个指令会自动寻找当前目录下的Makefile
,makefile
等文件,并依据里面的规则执行。如果文件里有多条规则,那么第一条规则会被执行(默认规则)。
规则、依赖与vim整合
我们可能会希望连续make帮我们顺序执行一系列指令。这有两种方式可以做到:
首先是同一条规则下,允许运行多条指令(都必须用\t
开始)。
run:
gcc main.c -o main
./main
build:
gcc main.c -o main
我们给run
这条规则指定了两条指令,一条编译程序,另外一条运行程序。 当我们唤醒这个规则时,这些指令会依次执行。
$ make
gcc main.c -o main
./main
Hello World!
另一种方法是用依赖关系:
run: build
./main
build:
gcc main.c -o main
第一行的run: build
的意思是,run
这条规则依赖于build
这条规则,所以在run
之前需要先运行build
规则。
执行,会有一样的结果。
显然第二种方式要比第一种好,这跟重复代码要提炼成函数是一个道理的。
现在精彩的来了,用vim main.c
进入main.c
的编辑。然后用:make
命令,在vim里运行vim的make命令,你会发现程序也被执行了。
也就是说,我们可以在vim里通过make唤醒相关的makefile,这样我们就不必退出编辑器就可以看程序的执行结果了。
如果编译过程中有编译错误,退回vim之后,vim还会体贴地把光标移动到出问题的行,方便你定位错误。
重定向
我们来写一个简单的A+B
:
#include <stdio.h>
int main(){
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",a+b);
return 0;
}
然后:make
运行,你可以输入数据并得到结果。
但每次输入数据也是让我们很心烦的事,我们可以利用重定向来简化这个操作。
先在当前路径新建一个文件in.txt
,通过vim的命令:e in.txt
来新建一个文件(e表示打开文件,你还可以通过命令:bn
在文件中切换)。把你的输入放到这个txt
文件里:
1 2
然后:e makefile
打开makefile,修改run
规则为:
run: build
./main < in.txt
build:
gcc main.c -o main
把run
规则里的./main
改为./main < in.txt
。表示用in.txt
这个文件作为main
的输入(而不是用键盘来输入)。
然后:make
执行一下,你会发现不用你输入内容,Linux会自动将in.txt
的内容作为输入喂给main
,是不是方便了很多?
调试
到目前为止,如果你用熟悉了上面的内容,你会发现你的编码效率高了很多。但有个很尴尬的问题,就是调试。
正如编辑需要一个工具(vim),编译需要一个工具(gcc),构建需要一个工具(make),调试也要用到一个工具:gdb。
但再次之前我们还需要做一件事,编译debug版的程序。
我们打开makefile
,如果你之前没有关闭vim的话,可以用命令:bn
在打开的文件中切换。
找到构建的规则,改为:
build:
gcc -g main.c -o main
也就是为gcc
命令增加一个-g
的开关,这将会为代码假如调试信息,使我们可以将代码和对应的机器指令关联起来。
然后我们编译一下:make build
,生成可调试的文件。
接下来我们调试,一般我们很少在vim里进行集成调试(虽然不是不可以)。当你需要调试时,我建议你直接调用gdb
来调试,在vim里输入:!gdb ./main
命令,表明我们需要用gdb
调试./main
文件。最前面的!
表示请vim在shell(你可以理解为外面的命令行)里运行这条指令。
之后你可以看到gdb
被启动:
和VS很不同的一点是,gdb
是一个命令行的调试器,你需要通过输入指令来让调试。
我们先用命令layout src
切换到源代码视图:
此时你看不到任何源码,再用命令list main
把main
函数加载出来:
你可以看到对应的源代码和行号。我们通过b
来下断点:b 5
,代表在第5行打断点,你也可以通b <函数名>
来断某个函数:
当我们跑起来,到第5行时,就会断在这里让你查看内容。
我们让程序跑起来:r < in.txt
,r
表示运行程序,后面用 < in.txt
来进行输入重定向。当然你也可以不重定向,直接输入也可以。
当程序断住之后,要查看变量的值,可以用display <变量名>
来打印。这个显示在每次程序暂停时都会打印一次,方便你观察。
我们也可以通过n
命令来step over
,通过s
来step into
,这两个操作和VS的含义是一样的。
对于初学者,这些简单的指令已经足够你使用了。
如果要退出,用命令q
即可。