预备知识
安装vim:
(针对Ubuntu,使用 apt 源安装 vim)apt-get install vim
(针对 centos、redhat,使用 yum 源安装 vim)yum install vim
配置vim:
安装vim并配置 ~/.vimrc 文件使得vim能够支持语法高亮、自动缩进等等功能。目前使用的 vimrc 配置文件的内容如下,进行基本的 c/c++ 编程已经足够了(适用于类 UNIX 系统):
" 显示行号 set number " 显示标尺 set ruler " 历史纪录 set history=1000 " 输入的命令显示出来,看的清楚些 set showcmd " 状态行显示的内容 set statusline=%F%m%r%h%w [FORMAT=%{&ff}] [TYPE=%Y] [POS=%l,%v][%p%%] %{strftime("%d/%m/%y - %H:%M")} " 启动显示状态行1,总是显示状态行2 set laststatus=2 " 语法高亮显示 syntax on set fileencodings=utf-8,gb2312,gbk,cp936,latin-1 set fileencoding=utf-8 set termencoding=utf-8 set fileformat=unix set encoding=utf-8 " 配色方案 colorscheme desert " 指定配色方案是256色 set t_Co=256 set wildmenu " 去掉有关vi一致性模式,避免以前版本的一些bug和局限,解决backspace不能使用的问题 set nocompatible set backspace=indent,eol,start set backspace=2 " 启用自动对齐功能,把上一行的对齐格式应用到下一行 set autoindent " 依据上面的格式,智能的选择对齐方式,对于类似C语言编写很有用处 set smartindent " vim禁用自动备份 set nobackup set nowritebackup set noswapfile " 用空格代替tab set expandtab " 设置显示制表符的空格字符个数,改进tab缩进值,默认为8,现改为4 set tabstop=4 " 统一缩进为4,方便在开启了et后使用退格(backspace)键,每次退格将删除X个空格 set softtabstop=4 " 设定自动缩进为4个字符,程序中自动缩进所使用的空白长度 set shiftwidth=4 " 设置帮助文件为中文(需要安装vimcdoc文档) set helplang=cn " 显示匹配的括号 set showmatch " 文件缩进及tab个数 au FileType html,python,vim,javascript setl shiftwidth=4 au FileType html,python,vim,javascript setl tabstop=4 au FileType java,php setl shiftwidth=4 au FileType java,php setl tabstop=4 " 高亮搜索的字符串 set hlsearch " 检测文件的类型 filetype on filetype plugin on filetype indent on " C风格缩进 set cindent set completeopt=longest,menu " 功能设置 " 去掉输入错误提示声音 set noeb " 自动保存 set autowrite " 突出显示当前行 set cursorline " 突出显示当前列 set cursorcolumn "设置光标样式为竖线vertical bar " Change cursor shape between insert and normal mode in iTerm2.app "if $TERM_PROGRAM =~ "iTerm" let &t_SI = "<Esc>]50;CursorShape=1x7" " Vertical bar in insert mode let &t_EI = "<Esc>]50;CursorShape=0x7" " Block in normal mode "endif " 共享剪贴板 set clipboard+=unnamed " 文件被改动时自动载入 set autoread " 顶部底部保持3行距离 set scrolloff=3
如果还想更舒服地编程,可以使用vim插件实现高级自动补全,快速定位、美化vim等等...那么最好先学习github的使用(如搜索廖雪峰的github教程),并在github上搜索 k-vim 并一键安装。
完整的编译并执行cpp文件过程
(一)代码编写
1. 启动终端;
2. 输入vim test.cpp,新建了一个文件叫做“test.cpp”;如果以前已经建立过这个文件,则是打开这个名字的文件。
3. 默认进入的是命令模式,输入 i、a、o等进入编辑插入模式,分别对应于当前位置之前、之后插入和插入一行。
如果要删除当前正在编辑的那一行的内容(删除一个字符,删除一个字,删除一行),则必须按下esc键回到命令模式,分别使用x(删除一个字符)、dw(删除一个字)、dd(删除一行)来进行删除。
如果要撤销某此操作,回到命令模式,然后输入命令u(undo)来撤销操作;如果要恢复撤销的内容,则在命令模式下,输入命令":redo"或者是":Control键+r",在没有设置compatible的情况下,可以作多次的撤销和恢复;
4. 编辑结束,输入":w"表明存盘,然后输入“:q!”退出vim编辑器;也可以直接输入“:wq!”直接完成这两个步骤。
(二)代码编译运行
设“test.cpp”文件的内容是:
#include <iostream> int main(void) { std::cout << "hello, world" << endl; return 0; }
1. 对于这个.cpp文件,使用以下的命令进行文件的编译:
gcc -Wall test.cpp -o test -lstdc++ //必须加上 -lstdc++ 选项用来通知链接器链接静态库 libstdc++.a, //否则会因为找不到库函数而出错
或者直接使用编译c++(.cpp)文件专用的命令g++,如下:
g++ -Wall test.cpp -o test
该命令将文件‘test.cpp’中的代码编译为机器码并存储在可执行文件 ‘test’中。机器码的文件名是通过 -o 选项指定的,该选项通常作为命令行中的最后一个参数。如果被省略,输出文件默认为 ‘a.out’。
如果当前目录中与可执行文件重名的文件已经存在,则它将被复盖。
选项 -Wall 开启编译器几乎所有常用的警告──强烈建议你始终使用该选项。编译器有很多其他的警告选项,但 -Wall 是最常用的。当编写 C 或 C++ 程序时编译器警告非常有助于检测程序存在的问题。在最新几个版本的 g++ 里 -Wall 已是默认的选项,在编译时可无需再加入该选项,所以你也可以这么用:
g++ test.cpp
本例中,编译器使用了 -Wall 选项而没产生任何警告,因为示例程序是完全合法的。
另外:如果一开始建立了一个“test.c”的C语言类型的文件,内容如下;
#include <stdio.h> int main(void) { printf("Hello, world!/n"); return 0; }
编译时使用“gcc -Wall test.c -o testc”命令。另外必须注意的是,在c文件中不能出现c++的库,比如#include <iostream.h>就会报错,但是cpp文件包含c语言的库却是可以的。
2. 运行:
./test
这个命令将可执行文件载入内存,并使 CPU 开始执行其包含的指令。 路径“./”指代当前目录,因此“./test” 载入并执行当前目录下的可执行文件 ‘test’。
运行结果为:
hello, world
(三)编译多个源文件 (可跳过)
1. 多源文件示例
将上面的"test.cpp"分解为三个不同的文件‘main.cpp’、‘test_fn.cpp’和头文件‘test.h’。
(1)主程序‘main.cpp’如下:
#include "test.h" int main() { test("hello world!"); return 0; }
(2)函数声明文件"test.h"如下内容:
void test(const char* name);
(3)函数实现文件"test_fn.cpp"的内容如下:
#include <iostream> using namespace std; #include "test.h" void test(const char* name) { cout<<"Hello World!"<<endl; }
2. 多文件编译
g++ -Wall main.cpp test_fn.cpp -o newTest
本例中,我们使用选项 -o 为可执行文件指定了一个不同的名字 newTest。注意到头文件‘test.h’并未在命令行中指定,这是因为它已经在main.cpp中包含。
(四)简单的makeFile文件 (可跳过)
make命令 从 makefile(默认是当前目录下的名为‘makefile’的文件)中读取项目的描述。makefile指定了一系列目标(比如可执行文件)和依赖(比如对象文件和源文件)的编译规则,其格式如下:
目标: 依赖
命令
对每一个目标,make 检查其对应的依赖文件修改时间来确定该目标是否需要利用对应的命令重新建立。注意到,makefile 中命令行必须以单个的 TAB 字符进行缩进,不能是空格(纠正:就是空格而不是TAB)。
GNU Make 包含许多默认的规则(参见隐含规则)来简化 makefile 的构建。比如说,它们指定‘.o’文件可以通过编译‘.c’文件得到,可执行文件可以通过将‘.o’链接到一起获得。隐含规则通过被叫做make变量的东西所指定,比如 CC(C 语言编译器)和 CFLAGS(C程序的编译选项);在makefile文件中它们通过独占一行的 变量=值 的形式被设置。对 C++ ,其等价的变量是CXX和CXXFLAGS,而变量CPPFLAGS则是编译预处理选项。
1. 现在为上面的“编译多个源文件”示例创建一个简单的makefile文件,内容如下:
CXXC=g++ CXXFLAGS=-Wall newTest: main.o test_fn.o //使用了隐含规则 cpp-->o clean: rm -f newTest main.o test_fn.o
该makefile文件可以这样来读:使用 C++语言编译器 g++,和编译选项‘-Wall’,从对象文件‘test.o’和‘test_fn.o’生成目标可执行文件 newTest(文件‘test.o’和‘test_fn.o’通过隐含规则分别由‘test.c’和‘test_fn.c’生成)。目标clean没有依赖文件,它只是简单地移除所有编译生成的文件。rm命令的选项 ‘-f’(force) 抑制文件不存在时产生的错误消息。
2. 要使用该 makefile 文件,输入 make命令。不加参数调用make时,makefile文件中的第一个目标被建立,从而生成可执行文件‘newTest’,终端会有如下输出:
$ make g++ -Wall -c -o main.o main.cpp g++ -Wall -c -o test_fn.o test_fn.cpp g++ main.o test_fn.o -o newTest 运行该可执行文件: $ ./newTest Hello, world!
3. 一个源文件被修改要重新生成可执行文件,简单地再次输入 make 即可。通过检查目标文件和依赖文件的时间戳,程序 make 可识别哪些文件已经修改并依据对应的规则更新其对应的目标文件:
$ vim test.cpp $ make //重新make g++ -Wall -c -o test.o test.c //此时只make该被修改的文件test.cpp g++ test.o test_fn.o -o newTest
运行结果:
$ ./newTest
Hello, world!
4. 最后,移除 make 生成的文件,输入“make clean”,显示如下:
$ make clean
rm -f hello hello.o hello_fn.o
总结: makefile文件类似一个编译连接程序的批处理文件,所有的命令要作的事情写进一个叫做makefile的文件中,然后使用make命令可以执行这个类似批处理文件的文件makefile。一个专业的 makefile文件通常包含用于安装(make install)和测试(make check)等额外的目标。
本例子中涉及到的例子都足够简单以至于可以完全不需要makefile,但是对任何大些的程序都使用 makefile文件是很有必要的。
(五)链接外部库
库是预编译的目标文件(object files)的集合,它们可被链接进程序。静态库以后缀为‘.a’的特殊的存档文件(archive file)存储。
标准系统库可在目录 /usr/lib 与 /lib 中找到。比如,在类 Unix 系统中 C 语言的数学库一般存储为文件 /usr/lib/libm.a。该库中函数的原型声明在头文件 /usr/include/math.h 中。C 标准库本身存储为 /usr/lib/libc.a,它包含 ANSI/ISO C 标准指定的函数,比如‘printf’。对每一个 C 程序来说,libc.a 都默认被链接。
下面的是一个调用数学库 libm.a 中 sin 函数的的例子,创建文件calc.c:
#include <math.h> #include <stdio.h> int main (void) { double x = sin (2.0); printf ("The value of sin(2.0) is %f/n", x); return 0; }
尝试单独从该文件生成一个可执行文件将导致一个链接阶段的错误:
$ gcc -Wall calc.c -o calc /tmp/ccbR6Ojm.o: In function 'main': /tmp/ccbR6Ojm.o(.text+0x19): undefined reference to ‘sin’
函数 sin,未在本程序中定义也不在默认库‘libc.a’中;除非被指定,编译器也不会链接‘libm.a’。
1. 法一
为使编译器能将 sin 链接进主程序‘calc.c’,我们需要提供数学库‘libm.a’。一个容易想到但比较麻烦的做法是在命令行中显式地指定它:
函数库‘libm.a’包含所有数学函数的目标文件,比如sin,cos,exp,log及sqrt。链接器将搜索所有文件来找到包含 sin 的目标文件。一旦包含 sin 的目标文件被找到,主程序就能被链接,一个完整的可执行文件就可生成了:
$ gcc -Wall calc.c /usr/lib/libm.a -o calc
$ ./calc The value of sin(2.0) is 0.909297
可执行文件包含主程序的机器码以及函数库‘libm.a’中 sin 对应的机器码。
2. 法二
为避免在命令行中指定长长的路径,编译器为链接函数库提供了快捷的选项‘-l’。例如,下面的命令
$ gcc -Wall calc.c -lm -o calc
与我们上面指定库全路径‘/usr/lib/libm.a’的命令等价。
一般来说,选项 -lNAME使链接器尝试链接系统库目录中的函数库文件 libNAME.a。一个大型的程序通常要使用很多 -l 选项来指定要链接的数学库,图形库,网络库等。
如果想要使用c++11标准需要显示链接 -std=c++11,并保持 g++ 版本在4.8以上,如下
g++ test.cpp -std=c++11