C++编译、连接

Windows中我们常用vs来编译编写好的C和C++代码,vs把编辑器,编译器和调试器等工具都集成在这一款工具中。linux下,通常我们使用vim编辑器,然后用gcc和g++编译、链接生成可执行程序。

我们很难说 C++ 拥有独立的编译器,例如 Windows 下的微软编译器(cl.exe)、Linux 下的 GCC 编译器、Mac 下的 Clang 编译器(已经是 Xcode 默认编译器,雄心勃勃,立志超越 GCC),它们都同时支持C语言和 C++,统称为 C/C++ 编译器。对于C语言代码,它们按照C语言的方式来编译;对于 C++ 代码,就按照 C++ 的方式编译。

1、我们先看一下C++源代码到可执行文件过程:

1)预处理:

经过预处理,会产生一个没有宏定义,没有条件编译指令,没有特殊符号的输出文件,这个文件的含义同原本的文件无异,只是内容上有所不同。

  1. 处理#define宏指令,进行宏展开、替换;
  2. 处理#if... 条件编译指令,将不必要的代码过滤;
  3. 处理#include预编译指令,包含头文件;
  4. 删除注释;
  5. 添加行号,为了调试;

2)编译:

  1. 语法分析;
  2. 词法分析;
  3. 生成相应的汇编代码;

3)汇编:

将汇编代码转换成相应的机器语言,即:目标文件;

4)链接:

通过调用链接器来链接程序运行需要的一大堆目标文件,以及所依赖的其他库文件,最后形成可执行文件。

2、gcc和g++命令:

熟悉C++的人应该都知道,C++是C语言的超集,编写C/C++代码的时候,有人用gcc,也有人用g++,我们先来看看gcc和g++是否都能编译C++和C代码:

1)对于C文件:

gcc和g++所做的事情确实是一样的,g++在编译C文件时调用了gcc。

2)对于cpp文件:

对于下面的test.cpp:

#include <iostream>
using namespace std;
int main()
{
  cout<<"hello c++"<<endl;
  return 0;
}

预处理、汇编gcc和g++都是可以的;但是编译、链接gcc会报错,原因是代码中#include <iostream>是C++的标准库,g++使用C++的标准库将目标文件和 libstdc++ 库中的函数链接得到可执行文件,而gcc使用的是C的标准库,所以会报错。知道了这些,通过遵循源码的命名规范并指定对应库的名字,用 gcc 来编译链接 C++ 程序是可行的,如下例所示:gcc命令编译、连接:

gcc test.cpp -lstdc++ -o helloworld

通过选项 -l(小写L) 指定C++的动态库名,根据默认规则:前缀 lib 和后缀 .a 拼接成libstdc++.a。

总结:

gcc和g++的区别主要是在对cpp文件的编译和链接过程中,因为cpp和c文件中库文件的命名方式不同,所以gcc无法直接编译、连接C++程序。那为什么g++既可以编译C又可以编译C++呢,这是因为g++在内部做了处理,默认编译C++程序,但如果遇到C程序,它会直接调用gcc去编译。

 3、用g++ 进行编译步骤详解:

1)预处理 -E    (源文件->预处理文件)

g++   -E   hello.cpp   -o  hello.i

-o 选项指定生成的文件,这一步若不指定,则会在终端输出预编译后的文件,后面几步的-o  也是同理,就是指生成指定文件。

2)编译 -S      (大写,预处理文件->汇编语言文件)

g++   -S  hello.ii   或者 g++  -S  hello.cpp

默认生成hello.s

3)汇编 -c    (汇编语言文件->可重定向的目标文件)

g++  -c   hello.s 或者 g++  -c  hello.cpp

默认生成 hello.o  目标文件,为二进制形式

4)链接    多个.o文件->可执行文件

比如有1.cpp,2.cpp
g++ -c  2.cpp     //生成2.o
g++ -c  1.cpp     //生成1.o
g++  1.o   2.o    -o   hello.out    //直接1.o 跟上2.o(空格隔开),-o指定为hello,默认为a.out
或者
g++  1.cpp   2.cpp  -o  hello.out  
g++   *.o    -o   hello.out 
g++   *.cpp   -o  hello.out

4、g++命令:

4.1)编译、连接带有头文件、多个源文件的程序:

1)当我们只编译一个main.cpp文件时,直接输入:

g++ main.cpp -o main

2)多个源文件

c/c++都是分别编译的,所以多个源文件可以分别编译,然后再一起连接。例如:

g++ common.cpp main.cpp -o main

3)当我们需要编译一个头文件和一个源文件如:common.h和main.cpp文件时: 

3.1)假设common.h与main.cpp在同一文件夹下:

main.cpp中使用#include "common.cpp"引入,那么可以直接编译:

  g++ main.cpp -I ./ -o main 或 g++ main.cpp -o main

3.2)假设common.h在/home/user/include文件夹下:

A、main.cpp使用绝对路径或者相对路径引入(#include "/home/user/include/common.h"),然后使用下面命令编译:

g++ main.cpp -o main

B、main.cpp中使用#include "common.cpp"引入,在直接编译的时候用-I 指明路径(绝对路径或者相对路径):

g++ main.cpp -I /home/user/include/ -o main

总结:可以通过g++ -I参数指定头文件位置,也可以在源文件中指定头文件路径

注:使用g++命令编译链接时,后面不用跟头文件,因为头文件会在编译时直接展开在源文件中。

4.2)带有第三方库

1)编译链接的时候需要使用如下参数指定:

  • -L:指定库文件路径;
  • -l:指定库文件名字(根据默认的规则:前缀lib,后缀.a/so);
  • -I:(大小i)指定头文件(include)路径;

2)运行的时候:

  • 需要配置LIBRARY_PATH、LD_LIBRARY_PATH环境变量,
  • 或者在/etc/ld.so.conf文件中指定库文件路径(或者将库文件放到默认的库文件路径/lib、/usr/lib...),然后执行ldconfig刷新/etc/ld.so.cache;

4.3)调试

想要调试,我们需要生成具有调试信息可执行文件。在编译时要加一个编译器参数(-g)来添加调试信息。然后在使用gdb工具调试。

4.4)其他gcc/g++参数选项

  • -shared :指定生成动态链接库。
  • -fPIC :产生位置无关的代码,当产生共享库的时候(动态库),应该创建位置无关的代码,这会让共享库使用任意的地址而不是固定的地址。
  • -static :指定生成静态链接库。
  • -L:指定要连接的库所在的目录。
  • -l:指定链接时需要的库名(动态/静态),编译器查找连接库时有隐含的命名规则:即在给出的名字前面加上lib,后面加上.a/.so来确定库的名称。
  • -I:(大写i)指定头文件的文件夹。
  • -Wall :生成所有警告信息。
  • -ggdb :此选项将尽可能的生成gdb的可以使用的调试信息。
  • -g :编译器在编译的时候产生调试信息。
  • -o:指定执行文件的名字;
  • -E:预处理、-S:汇编、-c:编译成目标代码(.o);

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赶路人儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值