本文介绍如何在 Linux 平台,以一种“透明”的方式学习 C 语言。

创建个人 root 系统

所谓“个人 root”系统,其实就是避免把软件安装到系统路径。这样我们可以方便的查看 root 目录下的文件,审查所安装软件的具体行为,而不必到系统目录中查找。创建个人 root 系统还可以避免使用系统 root 权限。

创建 root 系统目录:

$ mkdir ~/root # 用于保存非系统程序库

将个人 root 系统目录添加到系统路径:

$ mkdir ~/root # 用于保存非系统程序库

其实,这样的个人路径,在类似 Ubuntu 的系统中已经默认存在了,即个人文件夹下的 .local 目录。如果你愿意,完全可以使用该目录,而且不需要去修改系统路径。

从源码编译程序库

学习 C 语言完全可以像学习 Python 那样,直接使用现成的库。在 C 语言几十年的发展过程中,除了标准库的更新外,还产生了无数质量上乘的第三方库。利用这些库,我们可以更愉快的编程了。

下面会以 GSL 库为例,介绍类似第三方库的安装和使用方法,为后续学习其他的库奠定基础。

$ wget http://mirrors.ustc.edu.cn/gnu/gsl/gsl-2.6.tar.gz
$ tar xvzf gsl-2.6.tar.gz
$ cd gsl-2.6
$ ./configure --prefix=$HOME/root # 使用 prefix 参数指定安装目录
$ make && make install

该程序库将被添加到个人 root 系统,可以去目录中查看具体安装了哪些东西。

构建包含库的 C 程序

编写测试程序:

// 文件名:gsl_erf.c
#include <math.h>        // erf, sqrt 等
#include <stdio.h>       // printf 等
#include <gsl/gsl_cdf.h>

int main() {
  double bottom_tail = gsl_cdf_gaussian_P(-1.96, 1);
  printf("Area between [-1.96, 1.96]: %g\n", 1 - 2 * bottom_tail);
}

编写 Makefile 文件,通过 -I 指定库的头文件搜索路径;通过 -L 指定库的搜索路径:

CFLAGS=-I${HOME}/root/include -g -Wall -std=gnu11 -O3
LDLIBS=-L${HOME}/root/lib -lgsl -lgslcblas -lm

或者使用 GSL 自带的配置信息,该命令会自动计算出相关的路径:

CFLAGS=`gsl-config --cflags` -g -Wall -std=gnu11 -O3
LDLIBS=`gsl-config --libs`

编译测试程序:

$ make gsl_erf

运行测试程序:

$ export LD_LIBRARY_PATH=$HOME/root/lib:$LD_LIBRARY_PATH # 指定库路径
$ ./gsl_erf
Area between [-1.96, 1.96]: 0.950004

对于运行时需要连接共享库的程序,和编译过程一样,同样需要指定库的路径,可以通过修改 LD_LIBRARY_PATH 变量实现。

关于 GCC 和 Makefile

Makefile 编译过程的套路一般为:

  • 设置编译器选项的变量:CFLAGS 为我们提供了编译器的一些选项
  • 设置连接器选项的变量:LDLIBS 为我们提供了连接器的一些选项。
  • 使用 make 等工具将变量转换成真正的编译和连接的命令

常用编译器选项:

选项 说明
-g 加入调试符号
-Wall 添加编译器警告
-std=gun11 编译器版本为 C11
-O3 优化等级为 3
-o 指定输出的文件名,默认文件名为 a.out

常用连接器选项:

选项 说明
-I(大写的 i) 添加头文件搜索路径
-L 添加库文件搜索路径
-l(小写的 L) 指定需要连接的库:-lgsl 自动连接名为 libgsl.a