开始你的编程之旅

xmut-lby大约 7 分钟

开始你的编程之旅

编译程序

在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这个指令会自动寻找当前目录下的Makefilemakefile等文件,并依据里面的规则执行。如果文件里有多条规则,那么第一条规则会被执行(默认规则)。

规则、依赖与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 mainmain函数加载出来:

你可以看到对应的源代码和行号。我们通过b来下断点:b 5,代表在第5行打断点,你也可以通b <函数名>来断某个函数:

当我们跑起来,到第5行时,就会断在这里让你查看内容。

我们让程序跑起来:r < in.txtr表示运行程序,后面用 < in.txt来进行输入重定向。当然你也可以不重定向,直接输入也可以。

当程序断住之后,要查看变量的值,可以用display <变量名>来打印。这个显示在每次程序暂停时都会打印一次,方便你观察。

我们也可以通过n命令来step over,通过sstep into,这两个操作和VS的含义是一样的。

对于初学者,这些简单的指令已经足够你使用了。

如果要退出,用命令q即可。