C++(Qt)软件调试---编译器及编译参数学习(4)

时间:2021-10-21 01:14:12

C++(Qt)软件调试—编译器及编译参数学习(4)

更多精彩内容
????个人内容分类汇总 ????
????C++软件调试、异常定位 ????

PDF版本下载

1、前言

1.1 编译器参数有什么用

编译器参数是用于指定编译器在编译代码时的一些选项和参数,以达到不同的编译效果。编译器参数的作用主要有以下几个方面:

  1. 指定目标平台:编译器可以通过指定目标平台的选项来针对不同的硬件和操作系统进行编译,以生成适合目标平台的可执行文件或动态链接库。
  2. 优化编译效果:编译器可以通过优化选项来对代码进行优化,以提高代码的运行效率和执行速度。
  3. 控制编译过程:编译器参数可以控制编译过程中的一些行为,如指定输出文件名、生成调试信息、指定头文件搜索路径、链接库文件等。
  4. 生成调试信息:编译器可以通过调试信息选项来生成调试信息,以方便程序员在调试程序时查看变量的值、函数的调用栈等信息。
  5. 控制警告信息:编译器可以通过警告控制选项来控制编译过程中产生的警告信息,以帮助程序员发现代码中的潜在问题。

总之,编译器参数对于编译器的使用和代码的优化都非常重要,可以帮助程序员更好地控制和优化代码的编译过程,提高代码的质量和性能。

1.2 学C++软件调试为什么要先学编译器参数

在学习C++软件调试之前,了解编译器参数是非常重要的。因为编译器参数决定了程序编译的行为,包括编译器如何处理源代码、如何生成目标代码、如何链接库文件等等。

如果不了解编译器参数,可能会导致以下问题:

  1. 编译错误:由于编译器参数的错误使用,可能导致编译错误,导致程序无法编译通过。
  2. 目标代码错误:由于编译器参数的错误使用,可能导致生成的目标代码出现错误,导致程序无法正常运行。
  3. 性能问题:编译器参数的不合理使用,可能导致程序性能下降。
  4. 调试困难:由于编译器参数的错误使用,可能导致生成的目标代码缺少调试信息,导致调试过程困难。

因此,学习编译器参数可以帮助我们更好地理解和掌握C++程序的编译过程,更好地解决编译和调试过程中的问题,提高程序的性能和可维护性。

2、GCC

1.1 GCC是什么

GCC(GNU Compiler Collection)是一套开源的编程语言编译器,可以编译C、C++、Objective-C、Fortran、Ada和其他语言的源代码。GCC是GNU计划的重要组成部分之一,也是GNU*软件基金会的标志性项目之一。

GCC最初由Richard Stallman创建于1984年,它的目标是提供一个*、开源、高质量的编程语言编译器,支持多种编程语言和多种平台。GCC采用了模块化设计,允许用户根据需要选择编译器的不同部分,以便在不同的平台上生成高效、优化的机器码。

GCC具有多种优点,包括高度可移植性、高质量的代码生成、强大的优化功能、丰富的语言支持和广泛的平台支持。GCC已经成为许多操作系统和软件开发项目的标准编译器,包括GNU/Linux、FreeBSD、NetBSD、OpenBSD、macOS、Windows等。

同时,GCC也是许多其他开源项目的基础,例如GNU工具集、LLVM等。GCC的源代码可以免费获取、使用和修改,符合*软件的精神和原则,是*软件社区的重要贡献之一。

1.2 G++是什么

g++是GCC(GNU Compiler Collection)编译器集合中的一部分,它是GCC的C++编译器,可以编译C++语言的源代码并生成可执行文件。

g++支持C++98、C++11、C++14、C++17等多个版本的C++标准,并提供了丰富的编译选项和参数,可以对代码进行优化和调试,生成高效、稳定的可执行文件。

g++具有多种优点,包括高度可移植性、丰富的C++语言支持、强大的优化功能和广泛的平台支持。g++也是许多操作系统和软件开发项目的标准C++编译器,包括GNU/Linux、FreeBSD、NetBSD、OpenBSD、macOS、Windows等。

在Linux和Unix平台上,使用g++编译C++程序是一种常见的做法。例如,在Ubuntu上,可以使用以下命令安装g++:

sudo apt-get install g++

安装完成后,就可以使用g++命令编译C++程序了。例如,编译一个名为hello.cpp的程序,可以使用以下命令:

g++ -o hello hello.cpp

该命令将生成一个名为hello的可执行文件,可以使用以下命令运行:

./hello

1.2 编译器参数详细资料和概述

  • 详细参数说明:中文文档
  • 详细参数说明:英文官方文档
  • 官方文档中GCC和G++的参数非常多,但是大多数我们都用不到,只需要了解常用的就可以了;
  • 在这里学习主要以C++、Qt为主,所以使用的大多数为GCC/G++通用的参数,如果有不通用的会单独讲解;
  • 在Linux下可用使用g++ --help命令查看g++的用法和部分选项;

1.3 常用编译器参数

  • 以下是GCC/G++常用编译器参数:

    1. -E:预处理阶段(Preprocessing):在该阶段中,预处理器会根据指定的命令行选项(例如宏定义、头文件搜索路径等)将源代码转换为预处理后的代码文件。

      • 例如:g++ -E source.cpp -o output.i
    2. -S:编译阶段(Compilation)表示生成汇编代码文件,而不进行汇编和链接操作。生成的汇编代码文件通常以.asm或.s为扩展名。该文件包含了汇编代码和与之对应的源代码行号和注释。

      • 例如:gcc -S source.i -o source.s
    3. -c:汇编阶段(Assembly):在该阶段中,汇编器将汇编代码转换为目标文件,该目标文件包含了机器代码和其他一些必要的信息。

      • 例如:g++ -c source.s -o output.o
    4. -o:链接阶段(Linking):指定输出文件名,执行该命令后,会生成一个名为output的目标文件,该文件包含了编译后的机器代码和其他必要的信息。可以将该目标文件与其他目标文件一起链接,生成可执行文件。

      • 例如:g++ source.o -c output 或者 g++ main.cpp -o main
    5. -g:使用"-g"参数编译源文件时,G++编译器会在目标文件中生成调试信息,包括变量名称、函数名称、行号等信息。这些调试信息可以在调试器中使用,方便我们在调试程序时定位问题。

      • 的-g选项有四个等级,分别是-g0、-g1、-g2和-g3;
      • -g0:生成最小的调试信息,只包括行号和文件名等基本信息;
      • -g1:生成一般的调试信息,包括局部变量和全局变量的名称和类型等信息;
      • -g2:生成更多的调试信息,包括函数内联和调用的详细信息等;
      • -g3:生成最详细的调试信息,包括嵌套类型、模板实例化和静态变量等信息。
      • 一般来说,使用-g选项会影响程序的执行速度和可执行文件的大小。调试信息越详细,生成的可执行文件就会越大,执行速度也会越慢。因此,在实际开发中,应根据需要选择合适的-g等级,以平衡可执行文件的大小和调试信息的详细程度。在生产环境中,应该避免使用-g选项,而是使用优化选项生成更小、更快的目标文件。
    6. -Wall:使用"-Wall"参数编译源文件时,G++编译器会输出所有警告信息,包括未声明变量、类型转换问题、类型不匹配等等问题。这些警告信息可以帮助我们发现代码中可能存在的问题,及早修复它们。

    7. -Werror:使用"-Werror"参数编译源文件时,G++编译器会将所有警告信息视为错误,即在编译过程中遇到警告即停止编译。这可以帮助我们避免可能存在的问题,强制我们编写更加健壮的C++程序。

    8. -std=:指定编译器使用的C++标准,如果不指定"-std="参数,则默认为C++98。

      • -std=c++98:使用C++98标准;
      • -std=c++03:使用C++03标准;
      • -std=c++11:使用C++11标准;
      • -std=c++14:使用C++14标准;
      • -std=c++17:使用C++17标准;
      • -std=c++20:使用C++20标准。
    9. -I:使用"-I"参数编译源文件时,G++编译器会在指定的目录中寻找头文件。如果头文件不在当前目录下,或者在其他指定的目录中,我们就需要使用"-I"参数来告诉编译器头文件的位置。

      • 例如:g++ -I /path/to/header main.cpp -o main
    10. -L:使用"-L"参数编译源文件时,G++编译器会在指定的目录中寻找库文件。如果库文件不在默认的系统路径下,我们就需要使用"-L"参数来告诉编译器库文件的位置。

      • 例如:g++ main.cpp -L /path/to/library -lmylib -o main
    11. -l:用于指定链接的库文件名,即告诉编译器链接哪个库文件。使用"-l"参数编译源文件时,G++编译器会在指定的库文件搜索路径中寻找指定的库文件名,并将其链接到可执行文件中。

    12. -O:启用优化,分别对应不同的优化级别,在使用-O选项时需要注意,优化级别越高,编译时间越长,同时也可能导致编译错误。因此,应根据实际情况选择适当的优化级别。。

      1. -O0:不进行任何优化,生成的代码与原始代码相同;
      2. -O1:启用基本优化,包括删除未使用的函数和变量、使用内联函数、基本块合并、简单的循环变换等;
      3. -O2:启用更高级别的优化,包括函数内联、循环展开、常量传播等;
      4. -O3:启用*别的优化,包括更多的函数内联、更大范围的循环展开、更多的常量传播、更多的代码重排等;
      5. -Os:优化代码大小,尽可能减小生成的目标文件的大小;
      6. -Ofast:启用所有优化,但可能会违反C++标准,例如缺少精度保证。
    13. -D:使用-D选项可以在编译时定义一个宏,该宏可以在源代码中使用。例如:

      #include <iostream>
      using namespace std;
      
      int main() {
      #ifdef DEBUG
          cout << "Debugging mode" << endl;
      #endif
          cout << "Hello, world!" << endl;
          return 0;
      }
      
      • 使用命令g++ -DDEBUG hello.cpp -o hello编译后,执行输出为:Debugging mode;
      • 如果定义的宏有值,则使用=链接,例如:g++ -DDEBUG=1 hello.cpp -o hello
    14. -U:用于取消预定义的宏定义。预定义的宏定义通常由编译器或标准库提供,可以在代码中直接使用,无需进行宏定义。使用-U选项可以取消预定义的宏定义,以便在代码中重新定义该宏。

      • 使用-U选项的语法为:g++ -U macro_name [other options] file...
      • 其中,-U是选项名称,macro_name是要取消的宏定义名称,[other options]是其他编译选项和源代码文件;
      • 例如:g++ -U __cplusplus hello.cpp -o hello
    15. -fPIC:生成位置无关代码,方便动态链接,常用于编译动态链接库(shared library)。通常,动态链接库需要在不同的进程*享,因此需要使用位置无关代码。在Linux和Unix系统中,动态链接库的文件名通常以.so为后缀名。

      • 例如:g++ -fPIC -c hello.cpp -o hello.o,执行该命令后,会生成一个名为hello.o的目标文件,该文件包含了位置无关代码和其他必要的信息。
    16. -shared:用于生成动态链接库(shared library)。使用-shared选项将多个目标文件链接在一起生成动态链接库。

      • 例如:假设有两个名为hello1.o和hello2.o的目标文件,可以使用以下命令将它们链接为动态链接库libhello.so:g++ -shared hello1.o hello2.o -o libhello.so
    17. -march:用于指定生成的目标代码的目标指令集架构。使用-march选项可以生成特定的目标代码,以利用目标机器上的特定指令集。

      • -march选项的语法为:g++ -march=arch [other options] file...
      • 其中,arch是目标指令集架构的名称。可以使用g++ --help=target命令查看可用的架构名称;
      • 例如:g++ -march=i386 hello.cpp -o hello
    18. -pthread:用于在编译和链接时添加线程支持。使用-pthread选项可以将POSIX线程库(pthread)链接到程序中,以实现多线程的功能。

      • 例如:g++ -pthread hello.cpp -o hello
    19. -m32/-m64:指定生成32位或64位程序。

      • 例如:g++ -m32 -o myprog myprog.cpp;
      • 但是直接编译会报错,需要先安装32位开发库和编译器。

    以上是G++常用的编译器选项,具体使用方法可以参考G++的官方文档。在实际使用中,根据不同的需求,可能还需要使用其他的编译器选项,需要根据具体情况进行选择。

3、MinGW

1.1 MinGW是什么

MinGW是一个Windows平台下的开发环境,它提供了一套GNU工具集,包括编译器、链接器、库文件等,可以用于开发C、C++等程序。

MinGW的全称是Minimalist GNU for Windows,它是GNU工具集在Windows平台下的移植版本。MinGW的主要特点是轻量级和简单易用,与Cygwin相比,它不需要安装额外的运行时库和DLL,所以可以直接在Windows系统下运行。另外,MinGW支持静态链接,可以将程序编译成单独的可执行文件,无需依赖外部库。

MinGW的主要组成部分包括:

  1. GCC编译器:支持C、C++、Objective-C等语言的编译。
  2. Binutils:包括链接器、汇编器、反汇编器等。
  3. GDB调试器:用于调试程序。
  4. MinGW-w64:支持64位Windows平台的工具集。
  5. MSYS2:包括一套Unix风格的shell、工具和库,可用于构建和安装软件包。

使用MinGW可以在Windows平台上开发各种类型的程序,包括命令行工具、图形界面应用程序、动态链接库等。MinGW还可以与各种集成开发环境(IDE)结合使用,如Code::Blocks、Eclipse等。

总的来说,MinGW是一个非常实用的开发工具,它能够帮助开发者在Windows平台上快速地创建高质量的应用程序。

1.2 MinGW和GCC的关系

MinGW(Minimalist GNU for Windows)是一个运行在Windows平台上的开源软件开发工具集,它是GCC(GNU Compiler Collection)编译器集合的移植和扩展。因此,MinGW和GCC之间有密切的关系。

GCC是一套开源的编程语言编译器,可以编译C、C++、Objective-C、Fortran、Ada和其他语言的源代码。GCC也是GNU计划的重要组成部分之一,也是GNU*软件基金会的标志性项目之一。GCC采用了模块化设计,允许用户根据需要选择编译器的不同部分,以便在不同的平台上生成高效、优化的机器码。

MinGW提供了一套完整的工具链,包括GCC编译器、GNU工具集、GNU调试器等,可以让开发者在Windows平台上进行跨平台的软件开发,生成可在Linux和Unix平台上运行的应用程序。

因此,可以说MinGW和GCC之间的关系是,MinGW是GCC编译器集合在Windows平台上的移植和扩展,提供了在Windows平台上进行跨平台的软件开发的解决方案。

MinGW中包括了GCC编译器、GNU工具集、GNU调试器等,可以让开发者在Windows平台上使用GCC编译器集合中的工具,编译和链接C、C++、Objective-C、Fortran、Ada等语言的程序。

1.3 编译器参数详细资料和概述

  • 由于MinGW是GCC编译器集合在Windows平台上的移植和扩展,所以MinGW编译器的绝大部分参数和GCC的相同,完全可以直接看GCC的文档;
  • 详细参数说明:中文文档
  • 详细参数说明:英文官方文档

1.4 常用编译器参数

  • MinGW的常用编译器参数和GCC的基本相同(详细说明可以看GCC部分):

    1. -c:指示编译器生成目标文件而不生成可执行文件。
    2. -o:指定输出文件名。
    3. -g:生成调试信息,用于程序调试。
    4. -O:优化选项,可以提高程序执行效率。
    5. -I:指定头文件路径。
    6. -L:指定库文件路径。
    7. -l:指定需要链接的库文件。
    8. -Wall:显示所有警告信息。
    9. -Werror:将所有警告信息视为错误。
    10. -std:指定使用的C/C++标准。
    11. -m32/-m64:指定生成32位或64位程序。
    12. -shared:生成共享库。
    13. -static:生成静态库。
    14. -fPIC:生成位置独立的代码,用于共享库的编译。

    以上参数只是常用的一部分,更多详细的参数可以参考GCC编译器的文档。需要注意的是,Mingw使用的是GCC编译器,这些参数同样适用于Mingw。

4、MSVC

1.1 MSVC是什么

MSVC是Microsoft Visual C++的缩写,是由微软公司开发的C/C++编程语言集成开发环境(IDE),主要用于Windows操作系统上的应用程序和系统程序的开发,也支持对.NET Framework的开发。

MSVC提供了强大的代码编辑器、调试工具、代码分析器等功能,可以帮助开发者更高效地开发和调试程序。同时,MSVC也支持多种编译器选项和优化选项,可以生成高效的代码,提高程序的性能。

除了C++语言,MSVC还支持其他编程语言,如C#、VB.NET等。同时,MSVC也支持多种应用程序类型的开发,如控制台程序、Windows桌面应用程序、Windows服务、Web应用程序等。

总之,MSVC是由微软公司开发的C/C++编程语言集成开发环境,主要用于Windows操作系统上的应用程序和系统程序的开发,具有强大的代码编辑器、调试工具、代码分析器等功能。

1.2 MSVC和GCC的区别

MSVC和GCC都是常用的编程语言集成开发环境(IDE)。它们的主要区别如下:

  1. 平台支持:MSVC主要用于Windows平台上的应用程序和系统程序的开发,而GCC可以在不同的操作系统上使用,如Linux、Unix、Windows等。
  2. 编译器:MSVC使用微软公司自己的编译器**(cl.exe)**,而GCC使用GNU编译器。GCC是一个跨平台的编译器,可以在不同的操作系统上使用,并且支持多种编程语言,如C、C++、Fortran等。
  3. 开发环境:MSVC提供了一个完整的集成开发环境,包括代码编辑器、调试工具、代码分析器等功能,而GCC主要是一个编译器,需要结合其他工具来完成开发过程。
  4. 性能:在某些情况下,MSVC生成的代码比GCC快,因为MSVC使用了一些专门为Windows平台优化的技术。但在其他情况下,GCC生成的代码可能更快。
  5. 开源性:GCC是一个开源的编译器,可以*地使用和修改,而MSVC是一个商业软件,需要购买许可证才能使用。

总之,MSVC和GCC都是常用的编程语言集成开发环境,它们的主要区别在于平台支持、编译器、开发环境、性能和开源性等方面。选择使用哪个编程语言集成开发环境,需要根据具体的需求和开发平台来进行选择。

1.3 cl.exe是什么

cl.exe是Microsoft Visual C++(MSVC)的C/C++编译器,是MSVC的核心组件之一。

cl.exe支持多种C/C++标准,包括C89、C99、C++98、C++03、C++11、C++14、C++17等。它还支持多种编译器选项和优化选项,以生成高效的代码。同时,cl.exe还提供了强大的调试功能,可以帮助开发者更高效地进行代码调试。

除了C/C++语言,cl.exe还支持其他编程语言和编译器,如C#、VB.NET和F#等。在使用不同的编程语言和编译器时,需要根据具体的需求和项目来进行选择。

在Windows操作系统中,cl.exe可以通过Visual Studio Command Prompt或Developer Command Prompt来使用。这些命令提示符提供了一组环境变量和工具,以便于使用cl.exe和其他MSVC工具进行开发。

1.4 LINK链接器是什么

LINK是MSVC(Microsoft Visual C++)编译器套件中的一个组件,也叫做链接器(linker),用于将编译器生成的目标文件(object files)链接成可执行文件(executable files)或库文件(library files)。

在编译源代码时,编译器会将源代码转换为目标文件,这些目标文件包含了代码、数据和符号等信息。

LINK会将这些目标文件组合起来,生成一个可执行文件或库文件。

LINK通过解析符号来确定目标文件之间的依赖关系,并将它们组合成一个文件,同时还需要解决重定位问题,即对于引用其他目标文件中的符号的目标文件,如何调整这些符号的地址,以使它们在运行时能够被正确访问。

LINK提供了丰富的选项,以便开发人员可以根据需要进行灵活的配置。

例如,可以通过/link选项指定需要链接的库文件,通过/entry选项指定程序入口点等等。

LINK还支持多种可执行文件和库文件的格式,例如Windows平台上的PE格式、Linux平台上的ELF格式等。

总的来说,LINK是MSVC编译器套件中非常重要的组件之一,它可以将编译器生成的目标文件组合成一个完整的可执行文件或库文件,为开发人员提供了非常方便和灵活的开发环境。

1.5 编译器详细资料 和概述

1.6 MSVC编译器常用参数

  • 以下是MSVC编译器常用的参数:

    1. /c:只编译不链接,生成目标文件(object file)。
    2. /EH:指定C++异常处理模型为C++标准异常处理模型。
    3. /MT:静态链接标准库。
    4. /MD:动态链接标准库。
    5. /Ox:启用最大优化级别。
    6. /Od:禁用优化。
    7. /W4:启用级别最高的警告。
    8. /I:添加头文件搜索路径。
    9. /D:定义预处理器宏。
    10. /U:取消已定义的预处理器宏。
    11. /GS:启用缓冲区安全检查。
    12. /Zi:生成调试信息。
    13. /Z7:生成旧版本的调试信息。
    14. /Zp:指定结构体成员的对齐方式。
    15. /Zl:禁用默认库名。
    16. /Zm:指定编译器堆栈大小。

    这些参数可以通过命令行方式使用,也可以通过Visual Studio等集成开发环境进行设置。需要注意的是,不同版本的MSVC编译器可能会有不同的参数选项,所以在使用时需要查阅相应版本的文档或帮助文件。

1.7 MSVC编译器参数使用-/的区别

在Windows平台上,命令行参数通常使用“/”作为前缀,例如“/c”、“/EHsc”等等。

而在Unix/Linux平台上,命令行参数通常使用“-”作为前缀,例如“-c”、“-Wall”等等。

在MSVC编译器中,既可以使用“/”作为前缀,也可以使用“-”作为前缀。

例如,“/c”和“-c”是等价的。这是因为MSVC编译器支持Unix/Linux风格的命令行参数格式,这样可以方便Unix/Linux开发人员在Windows平台上使用MSVC编译器。

需要注意的是,在使用MSVC编译器时,如果在命令行中使用“-”作为参数前缀,则需要使用“/”作为路径分隔符。

例如,“cl -I./include myfile.cpp”中,“-I”使用了Unix/Linux风格的参数格式,“./include”使用了Unix/Linux风格的路径格式。

但是,“cl /I.\include myfile.cpp”中,“/I”使用了Windows风格的参数格式,“.\include”使用了Windows风格的路径格式。

总的来说,MSVC编译器支持使用“/”和“-”作为参数前缀,但需要注意参数格式和路径格式的区别。

1.8 msvc链接器常用参数

  • MSVC链接器常用参数有以下几个:

    1. /OUT:指定输出文件名,格式为“/OUT:filename”;
    2. /PDB:用于指定生成的可执行文件或动态链接库的Program Database(PDB)文件的名称和路径。PDB文件包含了调试信息,用于在调试程序时提供更好的可读性和可用性。/PDB选项的常用参数包括:
      1. /PDB::指定生成的PDB文件的名称和路径。
      2. /Zi:生成完整的调试信息。该选项会自动启用/PDB选项。
      3. /ZI:生成完整的调试信息,并在PDB文件中包含编辑和编译信息。
      4. /Fd::指定生成的PDB文件的名称和路径,与/PDB选项类似。
      5. /FS:启用并行生成PDB文件模式,以提高编译速度。
    3. /LIBPATH:指定要在环境库路径之前搜索的路径,格式为“/LIBPATH:dir1;dir2;…”。
    4. /ENTRY:指定程序的入口点(main函数),格式为“/ENTRY:symbol”。
    5. /SUBSYSTEM:通知操作系统如何运行 .exe 文件,常用的取值有CONSOLE(控制台应用程序)和WINDOWS(Windows应用程序),格式为“/SUBSYSTEM:subsystem”。
    6. /NODEFAULTLIB:在解析外部引用时忽略所有(或指定的)默认库,格式为“/NODEFAULTLIB:library”。
    7. /DEBUG:生成调试信息,格式为“/DEBUG”。
    8. /MAP:生成链接映射文件,格式为“/MAP”。
    9. /INCREMENTAL:启用增量链接,可以加速链接过程,格式为“/INCREMENTAL”。
    10. /OPT:控制 LINK 优化,常用的取值有/OPT:REF(去除未使用的函数和数据)、/OPT:ICF(去除重复的代码)、/OPT:WIN98(兼容Windows 98)、/OPT:NOWIN98(不兼容Windows 98)等等。

    需要注意的是,不同版本的MSVC链接器可能会有一些差异,例如支持的选项、默认值等等。

    在使用链接器时,需要查阅相应版本的文档或帮助文件,以便了解其具体使用方法和选项。

    总的来说,MSVC链接器提供了丰富的选项,可以对程序进行定制化的链接,以满足不同的需求。