【c/c++】gcc/g++知识和常见问题解决方案

目录

(1)c/c++编译过程

(2)gcc/g++常用参数

(3)编译举例

(4)gcc常连接的动态库

(5)linux下cc与gcc的关系

(6)gcc和g++的区别

(7)gcc/g++ 优化标识 -O1 -O2 -O3 -Os -Ofast -Og的作用

(8)编译常见报错解决方案

1.gcc编译c++程序报错

2.编译c++出现对xxx未定义的引用

3.找不到对应的线程库

4.cannot find -lstdc++

5.linux下动态库名字格式不对

(9)运行可执行文件常见问题解决办法

1.某版本的CXXABI找不到

2.调用动态库找不到.so库

3.缺少libcrypto.so.10库

4.file too short问题


(1)c/c++编译过程

gcc编译C源码有四个步骤:

  1. 预处理(也叫预编译):宏定义展开、头文件展开、条件编译等,同时将代码中的注释删除,这里并不会检查语法。
  2. 编译:检查语法,将预处理后文件编译生成汇编文件。在这个阶段中,gcc首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc把代码翻译成汇编语言。
  3. 汇编:将汇编文件生成目标文件(二进制文件)。
  4. 链接:C语言写的程序是需要依赖各种库的,所以编译之后还需要把库链接到最终的可执行程序中去。

(2)gcc/g++常用参数

选项

含义

-o 可执行文件名

指定生成的输出文件名,比如可执行文件名或者二进制文件名等

-E

只运行 C 预编译器,即只执行头文件展开、宏替换和注释去掉的工作:gcc -E hello.c -o hello.i

-S

c文件变成汇编文件(将C代码转换为汇编代码):gcc -S hello.i -o hello.s

-c

编译但是不链接。只编译并生成目标文件。gcc -c hello.s -o hello.o

-std=c++11

语言标准,如-std=c++11表示采用2011 ISO C++标准

-g

在目标文件中嵌入调试信息,生成供调试用的可执行文件,以便gdb之类的调试程序调试,GNU 调试器可利用该信息。由于文件中包含了调试信息因此运行效率很低,且文件也大不少,因此一般调试时可加此选项,正式发布时可不加。

-O1

编译器优化级别控制。默认不做优化,即-O0。使用-O1, -O2, -O3,编译器优化程度依次增加,优化越高,编译时用时越长,但运行时效率越高。

-Wall

打开所有警告,生成所有警告信息

-w

不生成任何警告信息。

-shared

生成共享目标文件。生成动态库时需要用到。

-static

禁止使用动态库,优先使用动态库。

-I dir

大写的i。指定头文件所在的文件夹。dir是路径,表示把dir加到头文件搜索路径中。这个选项很重要,特别是在使用第三方库的时候,以及cpp文件与h文件不再同一个路径下的时候

-l

-l,小写的l,指定所使用到的函数库名。

链接到某个库,比如-lnetcdf_c++4

-L dir

-L,大写的l,指定函数库所在的文件夹。可以与-l配合使用,告诉编译器去哪里找到链接库

-fPIC

fPIC 的全称是 Position Independent Code, 用于生成位置无关代码。可以大写-fPIC,也可以小写-fpic。

(1)不加 fPIC 也可以生成 .so 文件,但是对于源文件有要求,例如因为不加 fPIC 编译的 so 必须要在加载到用户程序的地址空间时重定向所有表目,所以在它里面不能引用其它地方的代码。因此建议编译时加上这个选项。

(2)不用此选项的话编译后的文件(比如二进制目标文件、动态库文件等)是位置相关的,所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。

(3)不加这个选项更消耗内存,但是不加 fPIC 编译的 so 文件的优点是加载速度比较快。

-D 宏名

相当于给程序中加了一个宏

比如-D name ,预定义一个名为name 的宏,值为1。 

比如-D DEBUG,预定义一个名为DEBUG的宏,值为1。

-Dname =definition,预定义名为name ,值为definition 的宏。

(3)编译举例

第1种:四步合一

直接由源代码编译得到可执行文件

单个c文件:gcc main.c -o main

多个c文件:gcc main.c data.c tool.c -o main

第2种:源文件→二进制文件→可执行文件

# 由cpp文件汇编生成的二进制目标文件
g++ -c -O2 -fPIC DataTool.cpp -o DataTool.o
g++ -c -O2 -fPIC DealTool.cpp -o DealTool.o
g++ -c -O2 -fPIC main.cpp -o main.o


# 编译生成test_demo
g++ -O2 -fPIC main.o DataTool.o DealTool.o -o test_demo -ldl -lrt

(4)gcc常连接的动态库

-lz     是link libz,链接压缩库(Z)
-lrt    实时库(real time):shm_open系列
-lm     是link libm,链接数学库(math)
-lc     是link libc,链接标准C库(C lib)
-ldl    是显式加载动态库的动态函数库,如果你的程序中使用dlopen、dlclose等
-lnsl    需要链接libnsl.so, libnsl.so是C网络服务的库
-lclntsh 需要链接libclntsh.so,是orcale客户端编译的时候需要用到的一个库
-lpthread  线程库
-lsnmp++   网络管理库
-locci     是指Oracle C++ Call Interface对应的动态库,(OCCI)驱动程序

(5)linux下cc与gcc的关系

linux系统的C编译器为gcc,它是GNU推出的功能强大的编译工具,因为UNIX系统的编译器为cc,所以在Linux系统还保留一个链接cc,用于和UNIX的向后兼容。

gcc是GNU C Compiler的缩写。gcc(GNU C Compiler)编译器的作者是Richard Stallman,也是GNU项目的奠基者。

(6)gcc和g++的区别

(1)常用习惯与误区说明

值得一提的是,实际使用中我们更习惯使用 gcc 指令编译 C 语言程序,用 g++ 指令编译 C++ 代码。需要强调的一点是,这并不是 gcc 和 g++ 的区别,gcc 指令也可以用来编译 C++ 程序,同样 g++ 指令也可以用于编译 C 语言程序。

(2)编译c或者cpp时的区别

  • 对于gcc来说,后缀为.c的,gcc 把它当作是 c程序,后缀为.cpp 的,会认为是C++程序。
  • 对于g++来说,无论是.c还是.cpp,都当做c++程序。

gcc和g++都可以编译c++代码

  • 直接用g++
  • 用gcc,但是需要链接c++标准库:gcc -lstdc++。

(3)是否定义__cplusplus宏

  • __cplusplus这个宏只是标志着编译器将会把代码按c还是C++语法来解释。
  • gcc不会定义__cplusplus 宏,而g++会。如果后缀为.c,并且采用gcc编译器,则该宏就是未定义的,否则如果是g++,就是已定义。

(7)gcc/g++ 优化标识 -O1 -O2 -O3 -Os -Ofast -Og的作用

(1)-O,-O1

这两个命令的效果是一样的,目的都是在不影响编译速度的前提下,尽量采用一些优化算法降低代码大小和可执行代码的运行速度。并开启如下的优化选项:

-fauto-inc-dec 
-fbranch-count-reg 
-fcombine-stack-adjustments 
-fcompare-elim 
-fcprop-registers 
-fdce 
-fdefer-pop 
-fdelayed-branch 
-fdse 
-fforward-propagate 
-fguess-branch-probability 
-fif-conversion2 
-fif-conversion 
-finline-functions-called-once 
-fipa-pure-const 
-fipa-profile 
-fipa-reference 
-fmerge-constants 
-fmove-loop-invariants 
-freorder-blocks 
-fshrink-wrap 
-fshrink-wrap-separate 
-fsplit-wide-types 
-fssa-backprop 
-fssa-phiopt 
-fstore-merging 
-ftree-bit-ccp 
-ftree-ccp 
-ftree-ch 
-ftree-coalesce-vars 
-ftree-copy-prop 
-ftree-dce 
-ftree-dominator-opts 
-ftree-dse 
-ftree-forwprop 
-ftree-fre 
-ftree-phiprop 
-ftree-sink 
-ftree-slsr 
-ftree-sra 
-ftree-pta 
-ftree-ter 
-funit-at-a-time

(2)-O2

该优化选项会牺牲部分编译速度,除了执行-O1所执行的所有优化之外,还会采用几乎所有的目标配置支持的优化算法,用以提高目标代码的运行速度

-fthread-jumps 
-falign-functions  -falign-jumps 
-falign-loops  -falign-labels 
-fcaller-saves 
-fcrossjumping 
-fcse-follow-jumps  -fcse-skip-blocks 
-fdelete-null-pointer-checks 
-fdevirtualize -fdevirtualize-speculatively 
-fexpensive-optimizations 
-fgcse  -fgcse-lm  
-fhoist-adjacent-loads 
-finline-small-functions 
-findirect-inlining 
-fipa-cp 
-fipa-cp-alignment 
-fipa-bit-cp 
-fipa-sra 
-fipa-icf 
-fisolate-erroneous-paths-dereference 
-flra-remat 
-foptimize-sibling-calls 
-foptimize-strlen 
-fpartial-inlining 
-fpeephole2 
-freorder-blocks-algorithm=stc 
-freorder-blocks-and-partition -freorder-functions 
-frerun-cse-after-loop  
-fsched-interblock  -fsched-spec 
-fschedule-insns  -fschedule-insns2 
-fstrict-aliasing -fstrict-overflow 
-ftree-builtin-call-dce 
-ftree-switch-conversion -ftree-tail-merge 
-fcode-hoisting 
-ftree-pre 
-ftree-vrp 
-fipa-ra

(3)-O3

该选项除了执行-O2所有的优化选项之外,一般都是采取很多向量化算法,提高代码的并行执行程度,利用现代CPU中的流水线,Cache等

-finline-functions      // 采用一些启发式算法对函数进行内联
-funswitch-loops        // 执行循环unswitch变换
-fpredictive-commoning  // 
-fgcse-after-reload     //执行全局的共同子表达式消除
-ftree-loop-vectorize   // 
-ftree-loop-distribute-patterns
-fsplit-paths 
-ftree-slp-vectorize
-fvect-cost-model
-ftree-partial-pre
-fpeel-loops 
-fipa-cp-clone options

(4)-Os

这个优化标识和-O3有异曲同工之妙,当然两者的目标不一样,-O3的目标是宁愿增加目标代码的大小,也要拼命的提高运行速度,但是这个选项是在-O2的基础之上,尽量的降低目标代码的大小,这对于存储容量很小的设备来说非常重要。为了降低目标代码大小,会禁用下列优化选项,一般就是压缩内存中的对齐空白(alignment padding)

(5)-Ofast

该选项将不会严格遵循语言标准,除了启用所有的-O3优化选项之外,也会针对某些语言启用部分优化。如:-ffast-math ,对于Fortran语言,还会启用下列选项

-fno-protect-parens 
-fstack-arrays

(6)-Og

优化调试体验。 -Og应该是标准edit-compile-debug周期的优化级别选择,在保持快速编译和良好调试体验的同时,提供合理的优化级别。用于生成可调试代码,因为某些收集调试信息的编译器通道在以下位置被禁用 -O0。像-O0 -Og完全禁用了许多优化过程,因此控制它们的单个选项无效。除此以外-Og 使所有 -O1 优化标志,但那些可能会干扰调试的标志除外:

-fbranch-count-reg  
-fdelayed-branch 
-fdse  
-fif-conversion  
-fif-conversion2  
-finline-functions-called-once 
-fmove-loop-invariants  
-fssa-phiopt 
-ftree-bit-ccp  
-ftree-dse  
-ftree-pta  
-ftree-sra

(8)编译常见报错解决方案

1.gcc编译c++程序报错

Linux环境C++编译报错:undefined reference to `std::ios_base::Init::Init()

问题描述

/root/gcc11.3/include/c++/11.3.0/iostream:74:对‘std::ios_base::Init::Init()’未定义的引用
/root/gcc11.3/include/c++/11.3.0/iostream:74:对‘std::ios_base::Init::~Init()’未定义的引用

Linux Linux环境C++编译报错 undefined reference to `std::i

出现情况:在Linux系统,用gcc(C编译器)编译C++程序,会报标题的错误。

原因是用gcc编译c++程序时,应当链接的库文件为libstdc++.so,而不是默认的libc.so,因此需要用-lstdc++参数指明,否则会在链接时发生错误。

如: gcc myfirst.cpp -lstdc++

gcc mem_map.cpp mmap_w.cpp -o mmap_w -lstdc++

或者使用g++命令

g++ mem_map.cpp mmap_w.cpp -o mmap_w

2.编译c++出现对xxx未定义的引用

uttools-libhelper.cxx:(.text+0x23cd):对‘utadapter::ut_initxxxxx未定义的引用

collect2: 错误:ld 返回 1

总结一下C++链接错误“对函数或变量未定义的引用”解决办法:

  • 函数或变量所在的库,没有添加到link_directories,需要在CMakeLists.txt里面添加。
  • 模板函数或者模板类数据没有实例化,也可能导致这个问题,需要指定模板,对模板函数或模板类做实例化。
  • src子文件夹下的文件需要在CMakeLists.txt里面include,也就是说有可能executable文件link到source或者include文件时没有找到函数或变量所在的文件,所以说它们未定义。因此将函数或变量所在文件添加到source或者include中并link到可执行文件,即可解决。
  • 有时可能是需要连接的库是软链接,需要先重新生成软键,再进行编译。
  • c++类成员函数的定义时未加作用域。

3.找不到对应的线程库

undefined reference to symbol 'pthread_create@@GLIBC_2.2.5'

这个错误信息通常表示在链接时找不到对应的线程库。解决办法是在编译时添加 -pthread 选项来链接线程库。以下是一个示例代码:

gcc -pthread your_code.c -o your_output

4.cannot find -lstdc++

/usr/bin/ld: cannot find -lstdc++

需要安装gcc和g++

5.linux下动态库名字格式不对

动态库名字格式 libxxx.so

(9)运行可执行文件常见问题解决办法

1.某版本的CXXABI找不到

/lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found (required by............)

问题描述

原因分析

gcc动态库版本过老

解决办法

a. 查看gcc动态库版本

strings /lib64/libstdc++.so.6 | grep CXXABI

发现CXXABI最高版本只有1.3.7,没有1.3.9的。解决办法是高版本gcc的动态库替换老版本gcc的动态库。

查看libstdc++.so.6属性

ls -l /lib64/libstdc++.so.6

发现libstdc++.so.6是个软连接,是直接链接到libstdc++.so.6.0.19上去的,而libstdc++.so.6.0.19是老版本的动态库,所以下面要做的就是将libstdc++.so.6连接到新版本的动态库上去。

b.查找编译gcc时生成的最新动态库

执行以下命令,查找编译gcc时生成的最新动态库

find / -name "libstdc++.so.*"

其中/root/gcc11.3/lib64/libstdc++.so.6.0.29是我们新版本的动态库

查看其动态库,能否满足我们的要求

strings /root/gcc11.3/lib64/libstdc++.so.6.0.29 | grep CXXABI

可以看到CXXABI有1.3.9的,满足要求。

如果系统中没有相应的libstdc++.so.x.x.x文件或者不满足我们的要求,可以去下最新版本的RPM resource libstdc

http://www.rpmfind.net/linux/rpm2html/search.php?query=libstdc&submit=Search+...&system=centos&arch=

c. 将上面的最新动态库复制到/lib64/目录下

cp /root/gcc11.3/lib64/libstdc++.so.6.0.29 /lib64/

d. 重新将libstdc++.so.6连接到libstdc++.so.6.0.29上去

cd /lib64
rm -rf libstdc++.so.6
ln -s libstdc++.so.6.0.29 libstdc++.so.6

e. 默认动态库升级完成。重新运行以下命令检查动态库

strings /lib64/libstdc++.so.6 | grep 'CXXABI'

可以看到新的动态库确实链接上去了

2.调用动态库找不到.so库

问题提示

linux下调用动态库.so文件时提示:cannot open shared object file: No such file or directory

在使用第三方so库的时候需要引入到自己的项目中,在编译阶段是没问题的,但是一旦运行会报以下错误:error while loading shared libraries: xxxxxxx.so: cannot open shared object file: No such file or directory

查看该可执行文件需要的库是否存在

比如可执行文件名字叫test

ldd test

执行以上命令,它需要调用哪些动态库,以及该动态库是否存在

解决办法

设置LD_LIBRARY_PATH这个环境变量

由于操作系统在运行程序过程中的package搜索路径依赖于LD_LIBRARY_PATH这个环境变量,所以检查是否包括该路径:

export | grep LD_LIBRARY_PATH

如果没有,则添加:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:动态库所在目录路径

3.缺少libcrypto.so.10库

问题提示

mongo: error while loading shared libraries: libcrypto.so.10: cannot open shared object file: No such file or directory

查看缺少的库文件

ldd /data/usr/mongodb/bin/mongod

/lib64 目录下少了文件:libcrypto.so.10、libssl.so.10 

查看宿主机:

ll /lib64/libcrypto.so.1*

ll /lib64/libssl.so*

 发现libcrypto.so.10是软连接,真正的文件是libcrypto.so.1.0.2k 

解决方案

第①种:创建软链接

如果有libcrypto.so.1.0.2k 则在容器中创建软连接就可以了

第②种:直接复制过来

复制文件到当前目录。

懒得复制原名再创建软连接了,直接复制成新的名称

cp /lib64/libcrypto.so.1.0.2k libcrypto.so.10

cp /lib64/llibssl.so.1.0.2k libssl.so.10

4.file too short问题

问题描述

./testAPI: error while loading shared libraries: libNanoQuote.so: file too short

原因:拷贝的libNanoQuote.so的文件大小是0,于是出现了这个问题

解决办法:将正确大小的动态库libNanoQuote.so文件拷贝过来就好


end

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值