视觉SLAM十四讲读书笔记(4)P32-P39

本文详细解释了C++中的库类型,包括头文件库、静态库和动态库的概念及区别,介绍了Eigen库和OpenCV库的用途。同时讨论了API和ABI在软件开发中的角色,以及头文件和库文件的关系。此外,还涵盖了IDE如VisualStudio和Eclipse在C++开发中的应用,以及断点调试和g++命令行参数的使用。
摘要由CSDN通过智能技术生成

目录

Q:什么是库

Q:什么是eigen库

Q:什么是头文件库,除了这种还有什么库

Q:为什么头文件库不用编译,静态库和动态库都需要编译

opencv库

Q:动态库还是共享库

Q:SHARED什么意思

 libhelloslam.cpp

using namespace std

void printHello()

add_library生成库文件命名规则

Q:什么是API,什么是ABI

Q:头文件和库文件有什么关系和不同

libhelloslam.h

#ifndef LIBHELLOSLAM_H_

#define LIBHELLOSLAM_H_

#的作用

#endif

usehello.cpp

Q:什么是IDE,C++有哪些常见的IDE

Q:什么是断点调试

Q:g++命令有哪些参数

Q:什么是只编译不链接

Q:什么是目标文件

Q:如果忘记把库链接到可执行程序上,编译会报错吗?报什么样的错


Q:什么是库

A:库(Library)是一些可重用的代码模块,包含一组已编译的可执行指令,其目的是供其他程序使用。库可以包含函数、类、变量和其他可执行代码,它们能够简化程序设计并提高代码重用性。在软件开发中,库通常被用于处理常见的任务,例如字符串处理、网络通信、数据存储和图形绘制等。库可以被链接到一个应用程序中,从而使应用程序可以使用库中定义的函数和数据。库可以被编译成静态库或动态库两种形式。


Q:什么是eigen库

A:

Eigen是一个用于线性代数的C++模板库,提供了线性代数的各种算法和数据结构。Eigen的主要特点包括:

  1. 头文件库:Eigen是一个纯头文件库,可以直接将Eigen的头文件包含在代码中使用。

  2. 高性能:Eigen在编译期间使用模板元编程技术生成高效的计算代码,比手写的高性能线性代数代码更容易维护和重用。

  3. 易用性:Eigen的API设计简单易用,类似于Matlab和NumPy的接口,使得数值计算变得更加简单。

  4. 广泛支持:Eigen支持常用的矩阵和向量操作,例如矩阵乘法、逆矩阵、特征值分解、奇异值分解等,还支持稠密和稀疏矩阵,以及各种数值类型。


Q:什么是头文件库,除了这种还有什么库

A:

头文件库(Header-only library)是一种特殊的库,它没有任何二进制文件,只有一些头文件,用于在编译时生成对应的代码。

头文件库的优点在于它们不需要编译,因此在使用时非常方便,只需要将头文件复制到项目中即可。此外,由于头文件库的代码是直接嵌入到使用它们的程序中,因此它们的执行速度通常比静态库和动态库更快。

除了头文件库,常见的库还包括静态库和动态库。静态库和动态库都需要编译成二进制文件,并在程序运行时加载使用。静态库会将库的代码编译到可执行文件中,因此生成的可执行文件比较大,但在运行时不需要再加载库,执行速度较快。动态库则不会将代码编译到可执行文件中,而是在程序运行时动态加载,因此生成的可执行文件较小,但执行速度较慢。


Q:为什么头文件库不用编译,静态库和动态库都需要编译

头文件库通常是一些纯文本的头文件,只包含函数和变量的声明和定义,而没有实现。这些头文件库被其他源文件包含后,只是为这些源文件提供了函数和变量的声明和定义,而实际的实现是由其他库或者源文件提供的。因此,头文件库本身并不需要编译,只需要放在适当的位置被其他源文件引用即可。

而静态库和动态库都是包含了实际代码实现的二进制文件,需要经过编译、链接等步骤才能生成。静态库在链接时会被完整地拷贝到可执行文件中,而动态库则是在运行时动态加载,因此需要编译成二进制格式。


opencv库

OpenCV(Open Source Computer Vision Library)是一个跨平台的计算机视觉库,可用于图像处理、计算机视觉和机器学习等领域的开发。它是由英特尔公司发起并开源的,现在由一群志愿者负责维护和更新。

OpenCV支持多种编程语言,如C++、Python和Java等,提供了丰富的API,包括图像处理、计算机视觉、视频捕捉、深度学习等功能。OpenCV的主要优点在于其跨平台性和高效性,它可以在Windows、Linux、MacOS等多种操作系统上运行,可以充分利用计算机的多核处理器加速图像处理和计算。

OpenCV提供了各种功能强大的算法和工具,例如图像处理中的滤波、边缘检测、形态学变换、图像分割和图像拼接等,计算机视觉中的特征提取、目标检测、人脸识别、三维重建等,以及深度学习中的卷积神经网络、循环神经网络等。

OpenCV的应用十分广泛,包括机器人、智能交通系统、医学图像处理、安防监控、虚拟现实、游戏开发等领域。


Q:动态库还是共享库

A:动态库和共享库是同一个概念,表示被多个应用程序共享使用的库。在Linux中,通常使用.so作为动态库的扩展名。


Q:SHARED什么意思

A:在CMake中,SHARED表示创建一个共享库,也称为动态库。共享库是在运行时加载的,可以被多个程序共享使用,可以减少内存使用,提高程序的可维护性。共享库可以在编译时或运行时加载。在Linux系统中,共享库通常具有“.so”(shared object)扩展名。

如果没有指定库类型,CMake默认情况下会将库类型设置为静态库。因此,如果不显式地使用SHAREDSTATIC关键字,那么生成的库就是静态库。


 libhelloslam.cpp

#include <iostream>
using namespace std;

void printHello() {
  cout << "Hello SLAM" << endl;
}

这段代码是一个简单的库文件,包含了一个函数printHello。该库使用了iostream头文件和std命名空间,并在函数中输出了一句话。这个库可以被其他程序调用,以实现输出相同的信息。在实际使用中,可能还需要将这个库编译成静态库或动态库,供其他程序链接使用。


using namespace std

using namespace std是C++中的一个命名空间的语句,用于避免在代码中频繁使用std::这个命名空间前缀,可以简化代码书写。std::是C++标准库的命名空间,包含了各种C++标准库的类、函数和对象等。在使用标准库中的元素时,通常需要使用std::前缀来表示命名空间。例如,使用std::cout输出信息。而使用using namespace std;之后,就可以直接使用cout输出信息,而不需要std::前缀了。需要注意的是,using namespace std;会将std命名空间下的所有元素都引入到当前作用域中,因此可能会与其他命名空间下的元素发生冲突,造成不必要的问题。因此,在代码中应该谨慎使用using namespace语句,避免不必要的问题。

using namespace 是 C++ 中的一个命名空间使用指令,可以将一个命名空间中的所有名称引入到当前作用域中。

例如,在代码中使用 std::cout 输出信息,需要指定 std 命名空间,可以使用 using namespace stdstd 命名空间中的名称引入到当前作用域中,这样就可以直接使用 cout 输出信息。

需要注意的是,使用 using namespace 可能会导致命名冲突问题,因此不建议在头文件中使用该指令。一般来说,最好使用 using 指令,只引入需要使用的名称,而不是整个命名空间。例如,使用 using std::cout 只引入 cout 名称,而不是整个 std 命名空间。


void printHello()

void是一种C++中的数据类型,表示没有返回值。在函数定义中,void用来表示函数不返回任何值。

printHello()是一个函数名,是自定义的函数名。函数定义中的圆括号()表示函数的参数列表,这个函数没有参数。

整个定义可以理解为:定义了一个名为printHello,没有参数,返回类型为void的函数。


add_library生成库文件命名规则

在使用 add_library 生成库文件时,其命名规则通常遵循以下格式:

  • 静态库:lib<name>.a,其中 <name> 是库文件的名称。
  • 共享库:lib<name>.so.<major>.<minor>.<patch>,其中 <name> 是库文件的名称,<major><minor><patch> 分别表示主版本号、次版本号和修订号。

其中,静态库通常以 .a 作为扩展名,共享库则以 .so 作为扩展名。在共享库的名称中,<major><minor><patch> 的值通常是根据库文件的 API 版本号和 ABI 版本号确定的,这样可以避免库文件的二进制接口不兼容引起的兼容性问题。


Q:什么是API,什么是ABI

A:

API(Application Programming Interface)和 ABI(Application Binary Interface)是两个不同的概念。

API是指应用程序接口,它定义了软件组件之间的交互方式。在软件开发中,API通常用于描述函数、类、变量等可供其他程序调用的接口。API通常是由程序员编写的,用于描述程序的功能和使用方法,并提供相应的函数、类等接口给其他程序使用。

ABI是指应用程序二进制接口,它定义了在二进制层面上的接口规范,描述了不同二进制对象之间如何相互作用。ABI规范了二进制文件的格式、调用约定、数据类型大小和对齐等方面的细节。它是操作系统和底层库之间的接口标准,确保在不同平台和编译器下的二进制兼容性。

在编译程序时,编译器会根据ABI规范生成相应的二进制文件,以便在不同操作系统、不同编译器、不同硬件平台上运行。因此,了解ABI规范对于编写跨平台代码和编译不同平台的库文件非常重要。


Q:头文件和库文件有什么关系和不同

A:

头文件和库文件都是在编写程序时需要引用的外部资源。

头文件是一组函数、变量和结构体的声明和定义,其中只包含函数和变量的声明而没有实现,用于告诉编译器这些函数和变量的名称、参数类型和返回值类型,但是并不包含函数和变量的具体实现。程序编译时需要将头文件包含进来,以便在编译过程中进行语法检查和类型检查。头文件通常具有扩展名 .h 或 .hpp,例如 stdio.h、iostream.h 等。

库文件则是一组函数、变量和结构体的实现代码,用于提供给程序运行时调用。库文件分为静态库和动态库两种类型,静态库在程序编译时将库文件的代码嵌入到可执行文件中,而动态库则在程序运行时动态加载并链接库文件。

头文件和库文件之间的关系是,头文件提供了函数、变量和结构体的声明和定义,而库文件则提供了这些函数、变量和结构体的具体实现代码。因此,在程序编写过程中,需要包含相应的头文件,以便编译器在编译过程中识别函数、变量和结构体的声明,而在程序运行时需要链接相应的库文件,以便程序可以调用函数、变量和结构体的具体实现。

头文件是库文件的接口描述,其中包含了函数、变量、结构体等的声明。在使用库文件时,需要包含对应的头文件来告诉编译器这些接口的存在,并且在链接阶段需要将库文件与可执行文件链接在一起。可以把头文件看作是编译器和库文件的桥梁,帮助编译器正确地使用库文件提供的接口。


libhelloslam.h

#ifndef LIBHELLOSLAM_H_
#define LIBHELLOSLAM_H_
// 上面的宏定义是为了防止重复引用这个头文件而引起的重定义错误

// 打印一句hello的函数
void printHello();

#endif

这是一个简单的头文件,其中包含一个函数的声明:printHello()。头文件的命名约定通常为:libxxx.h,其中xxx是库的名称。该头文件中使用了预处理器指令#ifndef,其作用是判断该头文件是否已被包含进另一个文件中,如果是,则跳过该文件的编译,避免重复定义。#define是定义一个宏,用于防止头文件被重复引用。#endif#ifndef的结束指令。头文件的作用是提供函数和变量的声明,让编译器能够识别和链接库文件中的函数和变量。


#ifndef LIBHELLOSLAM_H_

#ifndef是一个预处理器指令,常用于在头文件中防止重复包含。

当我们在一个源代码文件中使用#include指令包含头文件时,预处理器会将头文件的内容复制到源代码文件中。如果一个头文件被包含多次,就会造成内容重复,进而导致编译错误或程序运行异常。使用#ifndef指令可以防止这种情况的发生。

#ifndef指令后面跟着一个宏定义,如果该宏没有被定义过,则执行#ifndef和#endif之间的代码,否则忽略#ifndef和#endif之间的代码。通常情况下,我们会用头文件的名称来定义这个宏,如#ifndef LIBHELLOSLAM_H_。

因此,当一个头文件被多次包含时,只有第一次包含时会执行#ifndef和#endif之间的代码,后面的包含则会忽略这部分代码。这样就能保证头文件中的内容不会被重复复制到源代码文件中,从而避免了编译错误和运行异常。


Q:什么是宏

A:宏(Macro)是一种在代码中定义的简单文本替换形式。它可以被用来定义一些常量、函数或语句等。预处理器会在编译代码之前,根据宏的定义在代码中进行相应的替换操作。在 C++ 中,宏通常使用 #define 进行定义。

LIBHELLOSLAM_H_ 是一个宏定义,它用来防止头文件被重复包含,这个宏定义会被预处理器替换成一个唯一的字符串。在编译器编译源文件时,当遇到 #ifndef LIBHELLOSLAM_H_ 时,如果 LIBHELLOSLAM_H_ 这个宏没有被定义过,那么就会将 #define LIBHELLOSLAM_H_ 定义成一个字符串,然后编译头文件里面的内容;如果这个宏已经被定义过了,就会跳过整个头文件,避免了头文件被重复包含的问题。因此,LIBHELLOSLAM_H_ 只是起到一个宏定义的作用,而不是将 printHello() 替换成 LIBHELLOSLAM_H_


#define LIBHELLOSLAM_H_

#define是C/C++中的预处理指令之一,用于定义一个常量或宏。在头文件中,通常使用#define来定义一个符号常量,以便在其他文件中使用该常量。#define指令有两个部分,第一个是符号名称,第二个是替换的文本。在预处理时,所有出现的符号名称都会被替换成文本。这样可以在代码中使用符号名称,而不必关心它们具体代表什么含义。

在这句中,#define 宏定义只是定义了一个符号常量,没有替换文本是因为它的目的不是为了替换文本,而是为了在后续代码中使用该符号名称表示某个常量或某段代码。在头文件中使用 #define 定义一个符号常量可以防止同一符号被多次定义,避免了编译错误。


#的作用

#是预处理指令的起始符号,在预处理阶段会被预处理器识别和处理。如果没有 #,预处理器会认为代码是普通的 C++ 代码,而不是预处理指令,这样就会导致编译错误。因此,# 是必不可少的预处理指令的起始符号,没有 # 是不行的。


#endif

#endif 用于结束条件编译,它表示上面的条件编译块结束了。在条件编译中, #if#ifdef#ifndef 后面必须要有对应的 #endif。否则编译器将无法识别代码的逻辑关系,报错或者产生编译错误。


usehello.cpp

#include "libHelloSLAM.h"

// 使用 libHelloSLAM.h 中的 printHello() 函数
int main(int argc, char **argv) {
  printHello();
  return 0;
}

这段代码是一个使用libHelloSLAM库的例子。首先,它通过#include指令引入了libHelloSLAM库的头文件libHelloSLAM.h。然后,在main()函数中,调用了在libHelloSLAM库中定义的printHello()函数。

由于使用了头文件,编译器在编译时会自动把对printHello()函数的调用解析为对库文件中相应函数的调用。因此,我们可以在程序中方便地使用库文件中定义的函数,而不需要了解其实现细节。


Q:什么是IDE,C++有哪些常见的IDE

A:

IDE全称为Integrated Development Environment,是指集成开发环境。它是一个软件应用程序,旨在为程序员提供一个集成的开发环境,包括代码编辑器、编译器、调试器和其他有用的工具,以帮助程序员在开发过程中更高效、更便捷地编写代码。

常见的C++的IDE有:

  1. Visual Studio:微软公司开发的IDE,是目前使用最广泛的IDE之一,包括Visual Studio Community、Visual Studio Professional、Visual Studio Enterprise等多个版本,能够进行C++、C#等语言的开发。

  2. Eclipse:开源的IDE,支持多种编程语言,包括Java、C++、Python等,支持多种平台,包括Windows、Linux和Mac OS X等。

  3. Code::Blocks:一个免费开源的跨平台C++集成开发环境,可在Windows、Linux和Mac OS X等多个平台上运行,具有易用性和可扩展性。

  4. Qt Creator:Qt公司开发的集成开发环境,主要用于开发Qt应用程序,但也可用于其他C++应用程序的开发,支持多平台。

  5. Xcode:苹果公司开发的IDE,支持多种语言,包括C++、Objective-C等,主要用于开发Mac OS X和iOS应用程序。

  6. CLion:JetBrains公司开发的IDE,专门用于C++开发,支持跨平台


Q:什么是断点调试

A:断点调试是一种调试程序的方法,可以在程序执行的某个位置暂停程序的执行,以便进行查看、修改变量值、单步执行等操作。通过断点调试可以更快地发现程序中的错误,并可以更好地理解程序的执行流程。在程序中设置断点的方式一般是通过IDE等开发工具的图形界面,或者在代码中添加特定的指令。常见的IDE中包含了设置断点、单步执行、变量查看等调试工具。


Q:g++命令有哪些参数

g++命令有很多参数,这里列出一些常用的参数:

  • -o <file>:指定输出文件名
  • -c:只编译不链接
  • -g:生成调试信息
  • -Wall:打开所有警告信息
  • -Werror:将所有警告都视为错误
  • -I <path>:添加头文件搜索路径
  • -L <path>:添加库文件搜索路径
  • -l <library>:链接指定的库文件
  • -std=<standard>:指定使用的C++标准,如-std=c++11
  • -pthread:启用多线程支持

以上只是一些常用的参数,g++还有很多其他参数可以参考官方文档或者通过man g++命令查看。


Q:什么是只编译不链接

在 C++ 编程中,只编译不链接(Compile Only)指的是只对源代码进行编译,生成目标文件,而不进行链接操作生成可执行文件或库文件。这个过程通常可以通过在编译命令中添加 -c 参数来实现。使用这个选项可以在修改源代码后快速地进行重新编译,因为只需要重新编译发生了修改的源文件,而不必重新链接整个程序。

只编译不链接的过程一般包括语法分析、语义分析、中间代码生成等步骤,但不包括目标代码生成和链接这两个步骤。目标代码生成是将中间代码转换成机器码的过程,链接是将多个目标文件合并成一个可执行文件或库文件的过程。


Q:什么是目标文件

目标文件(Object file)是编译过程中的一种中间产物,包含了源代码编译后的机器代码,但还没有链接到最终的可执行文件中。它们通常具有.o或.obj等文件扩展名。目标文件包含编译器为每个源文件生成的所有机器代码和数据,并包括必要的符号表和调试信息。

可执行文件(Executable file)是一个包含机器代码、数据和资源的文件,可以直接运行在操作系统上。它们通常具有.exe、.out、.app等文件扩展名。可执行文件是在链接器(linker)将所有目标文件和库文件链接在一起之后生成的。生成可执行文件后,就可以直接在操作系统上运行程序了。

目标文件是编译器将源代码编译生成的中间文件,包含了编译后的目标代码和一些元信息,例如符号表,用于链接成可执行文件或库文件。

在编译过程中,目标文件是不可避免的中间产物。虽然它们不是最终的可执行文件或库文件,但是它们包含了编译器所需的一些重要信息,例如符号表、重定位信息、代码段等,这些信息在链接过程中是非常必要的。

因此,即使在生成可执行文件或库文件后,目标文件也不会立即被删除。它们通常会被保留下来以备将来使用,例如在修改源代码后重新编译时,可以通过增量编译的方式,只编译修改过的文件,然后再链接之前生成的目标文件,从而节省编译的时间。


Q:如果忘记把库链接到可执行程序上,编译会报错吗?报什么样的错

A:如果忘记把库链接到可执行文件上,在编译时链接器(linker)会报错。具体的错误信息可能因编译器和链接器的不同而有所区别,但通常会提示找不到相关的符号(symbol)或链接错误(link error)等。例如,如果使用gcc进行编译链接,可以看到类似于以下的错误信息:

/tmp/ccvx4DW4.o: In function `main':
main.cpp:(.text+0x15): undefined reference to `printHello()'
collect2: error: ld returned 1 exit status

这个错误信息意味着在编译链接时,无法找到名为printHello()的符号,因此链接器返回了一个错误码1。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值