c++ 基础——预处理、编译、链接

c++支持四种编程范式:面向过程、面向对象、模板、函数式编程

#include <iostream>

using namespace std;

int add1(int a,int b){
    return a+b;
}

class ADD{
public:
    int operator()(int a,int b){
        return a+b;
    }
}add2;

template<typename T,typename U>
auto add3(T a ,U b) -> decltype(a+b){
    return a+b;
}

auto add4 = [](int a,int b) -> decltype(a+b) {return a+b;};

int main(){
    ADD add2;
    cout << add1(3,4) << endl;
    cout << add2(3,4) << endl;
    cout << add3(3,4) << endl;
    cout << add4(3,4) << endl;
}

预处理、编译与链接

g++ test.cc 这样的命令包含三个过程:

  • 预处理生成待编译的源文件,可以通过g++ -E test.cc -o tmp.cc单独执行预处理过程,从而查看待编译的源文件
  • 编译阶段检查语法错误,生成目标文件(.o),可通过nm -C test.cc 查看目标文件包含的符号列表
  • 链接阶段将声明与定义联系起来,并生成最终的可执行文件

预处理

预处理阶段主要是执行#开头的预处理命令,如#include#define 等,其中#include就是将头文件复制到源文件中。可以通过g++ -E test.cc -o tmp.cc单独执行预处理过程,从而查看待编译的源文件例如有以下文件test.cc

#include <cstdio>
using namespace std;

int add(int a, int b);
int sub(int a,int b){
    return a-b;
}
int main(){
    printf("%d\n",add(3,4));
    printf("%d\n",sub(5,3));
    return 0;
}

然后执行g++ -E test.cc -o tmp.cc 并查看tmp.cc文件,可以看到tmp.cc文件有接近一千行代码。

条件式编译

条件式编译是在预处理过程中,看条件是否满足来将某个分支的代码选择出来生成待编译的文件,对于不满足条件的分支则不加入待编译的文件。

函数说明
#ifdef DEBUG是否定义了DEBUG 宏
#ifndef DEBUG是否没有定义了DEBUG 宏
#if MAX_N == 4宏MAX_N是否等于4
#elif MAX_N == 5否则宏MAX_N是否等于5
#else否则
#endif条件式编译必须以它为结尾

例如如下示例

#ifdef DEBUG
int op(int a, int b ){
	return a+b;
}
#else
int op(int a, int b){
	return a-b;
}
#endif

然后可以在编译的时候加入宏定义 -DDEBUG来控制op函数使用哪个实现版本。

编译与链接

编译阶段主要是做语法检查,函数的声明主要就是用于编译阶段,函数的定义则作用于链接阶段,定义和声明中一般分别放在头文件和源文件中,以减少重复定义或者未定义的情况。

可以用nm -C test.o 命令查看编译后的符号列表,其中U开头表示的是其定义需要在外文件中找,而T开头表示test.o文件中已经定义。

使用g++进行编译:g++ -c test.cc,得到test.o文件后,我们使用nm -C test.o查看文件中定义的符号列表

xfchen@xfchen-dev:~/workspace/cplusplus$ nm -C test.o
                 U _GLOBAL_OFFSET_TABLE_
0000000000000016 T main
                 U printf
                 U add(int, int)
0000000000000000 T sub(int, int)

可以看到,T开头的是mainsub函数,这两个函数在文件中都是有定义的,但是printfadd函数都是没有定义的,因此是U开头的,由于编译主要在在做语法检查,因此此阶段不会报错。但是如果想要通过链接阶段,则需要一个包含add函数定义的.o文件,例如由add.cc 生成的add.o,则可以使用g++ test.o add.o进行链接,如果两个.o 文件出现相同的定义,则在链接时也会报错。

编译链接外部的静态链接库与头文件

假如使用的是googletest编译好的静态链接库lib/libgtest.a 和 头文文件include/gtest/gtest.h,测试程序代码test.cc如下

#include <gtest/gtest.h>

using namespace std;
int sub(int a,int b){
    return a-b;
}
TEST(test,sub){
    EXPECT_EQ(sub(4,3),1);
    EXPECT_GT(sub(5,3),1);
}
int main(){
    return    RUN_ALL_TESTS();
}

编译命令:g++ -I./include -L./lib test.cc -lgtest

解析:

  • -I参数,添加编译时搜索的路径,这样就能找到<gtest/gtest.h>
  • -L参数,添加链接时搜索的路径,这样就能找到lib目录下指定的链接库
  • -lgtest,会自动展开成 libgtest并寻找该文件,这样就能到lib/libgtest.a

googletest 编译时还需要加上-lpthread,以上只是示例

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值