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

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

更多精彩内容
👉个人内容分类汇总 👈
👉C++软件调试、异常定位 👈
👉PDF版下载 👈

1、前言

1.1 编译器参数有什么用

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

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

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

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

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

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

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

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

1.3 C++程序异常调试需要什么

在C++可执行程序调试时,需要包含以下信息:

  1. 符号表:符号表是一张记录程序中所有变量、函数、类等符号信息的表格。在调试时,通过符号表可以很方便地查找变量或函数的地址、类型、名称等信息,从而帮助我们定位程序中的问题。
    • gcc、Mingw编译器编译的可执行程序的符号表存放在可执行程序中;
    • MSVC编译的可执行程序符号表存放在pdb文件中。
  2. 调试信息:调试信息是编译器生成的一些额外信息,用于帮助调试器在调试时定位问题。调试信息包括源代码文件名、行号、变量名、函数名等信息。在调试时,调试器可以通过调试信息来显示源代码的行号或变量名等信息,从而帮助我们更加方便地理解程序的执行过程。
    • gcc、Mingw编译器编译的可执行程序的符号表存放在可执行程序中;
    • MSVC编译的可执行程序符号表存放在pdb文件中。
  3. 堆栈信息:堆栈信息记录了程序中所有函数的调用关系和栈帧信息。在调试时,调试器可以使用堆栈信息来定位程序的执行过程中发生的问题。
    • 动态调试时不需要,不会生成;
    • linux下gcc编译的程序堆栈信息存放在core文件中;
    • windows下msvc、mingw编译的程序堆栈信息存放在dump文件中。
  4. 可执行程序:可执行文件是程序的二进制文件,它包含了程序的代码和数据。调试器需要使用可执行文件来加载程序的符号表和源代码,以便在Core dump文件中定位问题。
  5. 源代码:Core dump调试需要对程序的代码有一定的了解,包括程序的结构、逻辑等。如果有源代码,则可以更方便地定位问题。

2、C++编译

1.1 C++编译过程

C++编译过程是将源代码转换成可执行程序的过程,通常包括四个步骤:预处理、编译、汇编和链接。

分别对应编译器中的预处理器、编译器、汇编器和链接器。

了解编译过程可以帮助我们更好地理解程序的编译、调试和优化。

下面分别介绍每个步骤的作用和具体过程:

1.1.1 预处理阶段

C++预处理阶段的主要作用是将源代码中的预处理指令(以符号“#”开头的语句)处理成实际的代码。

预处理器会去掉注释、展开宏、处理条件编译等。

预处理器还可以定义常量、宏、包含头文件等。

预处理阶段的具体过程如下:

  1. 去除注释:将源代码中的注释去除,包括单行注释(//)和多行注释(//)。
  2. 处理预处理指令:对源代码中的预处理指令进行处理,如#include、#define、#if、#else等。
  3. 处理宏定义:将源代码中的宏定义(#define)替换为相应的文本,以产生新的源代码文件。
  4. 处理条件编译指令:根据条件编译指令(#if、#ifdef、#ifndef等)的值确定哪些代码需要编译,哪些不需要编译。
  5. 处理头文件:将源代码中的头文件(#include)替换为相应的文件内容,以产生新的源代码文件。
  6. 生成预处理结果:将处理后的源代码保存为预处理结果,供编译器使用。

预处理器是由编译器自动完成的,不需要程序员手动干预。

预处理后的代码会生成一个临时文件,通常是以“.i”作为扩展名。

预处理阶段的作用是为编译器提供更加完整、准确的代码,为后续的编译、汇编和链接阶段打下基础。

1.1.2 编译阶段

编译阶段主要作用是将预处理文件转换成汇编代码。

编译器会对源代码进行词法分析、语法分析、语义分析和代码优化等操作,生成一个汇编代码文件。

汇编代码是一种低级语言,是机器语言的中间表示。

编译过程的具体步骤如下:

  1. 词法分析:将预处理文件分解成单词。单词是编程语言中的最小语法单位,包括关键字、标识符、常量、运算符等。
  2. 语法分析:对单词进行语法分析,生成语法树。语法树是一个树形结构,用于表示程序的语法结构,包括表达式、语句、函数等。
  3. 语义分析:对语法树进行语义分析,检查代码的正确性,并生成中间代码。语义分析包括类型检查、符号表管理、作用域分析等,用于保证程序的正确性和安全性。
  4. 优化:对中间代码进行优化,提高代码的执行效率。优化包括常量折叠、循环展开、代码块合并等,以减少程序的执行时间和空间消耗。
  5. 生成汇编代码:将优化后的中间代码转换成汇编代码。汇编代码是一种低级别的机器语言,用于描述程序的指令序列和数据操作。
1.1.3 汇编阶段

汇编阶段主要作用是将汇编代码转换成机器码。

汇编器会读入汇编代码文件,将其转换成机器语言指令,并生成一个目标文件。

目标文件包含可执行代码和数据,但还没有进行链接。

具体步骤如下:

  1. 词法分析:将汇编代码分解成单词。单词是汇编语言中的最小语法单位,包括指令、标号、操作数等。
  2. 语法分析:对单词进行语法分析,生成语法树。语法树是一个树形结构,用于表示汇编程序的语法结构,包括指令、标号、操作数等。
  3. 语义分析:对语法树进行语义分析,检查代码的正确性,并生成目标文件。语义分析包括符号表管理、地址计算、重定位信息等,用于生成可执行文件。
  4. 生成目标文件:将汇编代码转换成目标文件,包含机器码和符号表等信息。目标文件是可执行文件的中间文件,用于链接阶段
1.1.4 链接阶段

链接阶段的主要作用是将多个目标文件和库文件合并成一个整体,为程序的执行提供支持。

链接器通过符号解析、符号重定位、合并代码和数据段等步骤,将多个目标文件和库文件合并成一个可执行文件或库文件。

链接阶段的关键在于符号匹配和重定位,链接器需要正确地解析符号,并将其引用位置修改为定义位置,以保证程序能够正确运行。

具体步骤如下:

  • 符号解析:将所有目标文件和库文件中的符号进行解析和匹配。符号是程序中的变量、函数等标识符,链接器需要将其解析出来,并找到其定义或引用的位置。
  • 符号重定位:将所有目标文件和库文件中的符号进行重定位。重定位是将符号的引用位置修改为定义位置的过程,以便程序能够正确地运行。
  • 合并代码和数据段:将所有目标文件和库文件中的代码段和数据段进行合并。代码段是存放程序指令的区域,数据段是存放程序数据的区域,链接器需要将它们合并成一个整体。
  • 生成可执行文件或库文件:将合并后的代码和数据段生成可执行文件或库文件。可执行文件是可以直接运行的程序,库文件是为其他程序提供支持的代码库。

1.2 C++编译的四个阶段软件调试的影响

1.1.1 预处理阶段

预处理阶段会将源代码中的预处理指令进行处理,生成一个没有宏定义、没有条件编译指令、没有注释的代码文件。

这个过程中,预处理器会将代码展开并替换宏定义,同时还会删除注释和多余的空格。

预处理阶段不会改变源代码的结构和逻辑,因此不会对调试造成影响。

在调试时,可以使用预处理器生成的代码文件进行调试。

1.1.2 编译阶段

编译阶段会将源代码翻译成汇编语言,生成一些中间文件。

编译器会进行词法分析、语法分析、代码生成、类型检查等操作。

编译器在代码生成阶段会进行一些转换和优化操作,这可能会导致生成的汇编代码和源代码不同。

这时需要使用编译器的调试选项,如-g选项,生成调试信息。

如果需要在汇编代码中进行调试,那么需要熟悉汇编代码的语法和结构。

在调试时,可以使用编译器生成的中间文件进行调试。

1.1.3 汇编阶段

汇编阶段会将汇编代码翻译成机器码,并生成目标文件,这些操作不会影响调试。

汇编器会将汇编代码中的标号转换成地址,并将指令和数据进行组合。

在汇编阶段,可能会出现一些和源代码不同的东西,比如标号、寄存器名等。

如果需要在汇编代码中进行调试,那么需要熟悉汇编代码的语法和结构。

在调试时,可以使用汇编器生成的目标文件进行调试。

1.1.4 链接阶段

链接阶段会将多个目标文件合并成一个可执行文件。

链接器会将各个目标文件中的符号进行解析,并将它们连接起来。

链接器还会进行一些优化操作,如函数内联、函数去重、代码压缩等。

在链接阶段,可能会出现符号冲突或者符号丢失的问题。

这时需要使用链接器的调试选项,如-g选项,生成调试信息。

如果在调试时出现符号相关的问题,那么需要检查链接器的输出。

在调试时,可以使用链接器生成的可执行文件进行调试。

3、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++的用法和部分选项;
  • 使用g++ --help=common命令可以查看常用选项;

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++编译器会在目标文件中生成调试信息,包括变量名称、函数名称、行号等信息。这些调试信息可以在调试器中使用,方便我们在调试程序时定位问题(不同的级别编译的可执行程序大小区别很大,可与优化选项-O一起使用)。

      • 的-g选项有四个等级,分别是-g0、-g1、-g2和-g3;
      • -g:以操作系统的本机格式(stabs、COFF、XCOFF或DWARF)生成调试信息。GDB可以使用这些调试信息。默认级别为-g2;
      • -g0:不生成调试信息,不能用于调试;
      • -g1:生成的信息最少,足以在程序中不打算调试的部分进行回溯。这包括函数和外部变量的描述,以及行号表,但没有关于局部变量的信息。
      • -g2:生成更多的调试信息,包括函数内联和调用的详细信息、局部变量等(一般使用-g或者-g2就够了);
      • -g3:包括额外的信息,例如程序中存在的所有宏定义。某些调试器在使用时支持宏扩展。现在最新版的gcc编译器默认使用DWARF5,DWARF5是DWARF格式的最新版本,它在前几个版本的基础上增加了一些新的特性。然而,DWARF5并不支持展开宏定义。需要加上-gdwarf-2-gdwarf-3或者-gdwarf-4参数使用低版本的DWARF。
      • 一般来说,使用-g选项会影响程序的执行速度和可执行文件的大小。调试信息越详细,生成的可执行文件就会越大,执行速度也会越慢。因此,在实际开发中,应根据需要选择合适的-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:启用优化,分别对应不同的优化级别(0~3级)、优化选项,在使用-O选项时需要注意,优化级别越高,编译时间越长,同时也可能导致编译错误。因此,应根据实际情况选择适当的优化级别。(下面每个级别的优化项不一定对,实际优化项非常多,详细可以看官方链接

      1. -O0:表示取消所有优化选项,编译出的代码会比较大,但编译速度会较快,便于调试(默认);
      2. -O1:启用基本优化,包括删除未使用的函数和变量、使用内联函数、基本块合并、简单的循环变换等;
      3. -O2:启用更高级别的优化,包括函数内联、循环展开、常量传播等;
      4. -O3:启用最高级别的优化,包括更多的函数内联、更大范围的循环展开、更多的常量传播、更多的代码重排等;
      5. -Os:针对大小进行优化,尽可能减小生成的目标文件的大小;
      6. -Ofast:启用所有优化,但可能会违反C++标准,例如缺少精度保证;
      7. -Og:是在保留调试信息的同时进行优化的选项。优化调试体验。应该是标准编辑-编译-调试周期的优化级别,在保持快速编译和良好调试体验的同时提供合理的优化级别。以提高代码的执行效率,同时也方便调试;
      8. 可以使用g++ --help=optimizers命令查看编译器支持的-O选项有哪些。
    13. -s:从可执行文件中删除所有符号表和重新定位信息。(release模式可能会有)

    14. -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
    15. -U:用于取消预定义的宏定义。预定义的宏定义通常由编译器或标准库提供,可以在代码中直接使用,无需进行宏定义。使用-U选项可以取消预定义的宏定义,以便在代码中重新定义该宏。

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

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

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

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

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

      • 例如:g++ -m32 -o myprog myprog.cpp;
      • 但是直接编译会报错,需要先安装32位开发库和编译器。
    21. -Wl:选项用于将参数传递给链接器。这个选项可以将链接器参数作为g++编译器的参数来使用,以便在编译和链接过程中使用链接器特定的参数或选项。这个选项可以用于设置库路径、库文件名、链接器选项等。

      • 例如,要在链接时使用一个库文件,可以使用-Wl选项指定库文件路径和名称:
      • g++ -Wl,-L/path/to/library -Wl,-lmylib source.cpp -o program
      • 其中:-L/path/to/library -Wl,-lmylib就是链接器命令。

    以上是G++常用的编译器选项,具体使用方法可以参考G++的官方文档。

    在实际使用中,根据不同的需求,可能还需要使用其他的编译器选项,需要根据具体情况进行选择。

4、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:生成位置独立的代码,用于共享库的编译。
    15. -s:从可执行文件中删除所有符号表和重新定位信息。(release模式可能会有)
    16. -Wl:选项用于将参数传递给链接器。

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

5、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:使用 LIBCMT.lib 编译以创建多线程可执行文件。
    4. /MD:使用 MSVCRT.lib 编译以创建多线程 DLL。
    5. /Ox:不包含 /GF 或 /Gy 的 /O2 子集。
    6. /O1:创建小代码。
    7. /O2:创建快速代码。
    8. /Ob[n]:控制内联展开。
    9. /Od:禁用优化。
    10. /W4:启用级别最高的警告。
    11. /I:添加头文件搜索路径。
    12. /D:定义预处理器宏。
    13. /U:取消已定义的预处理器宏。
    14. /GS:启用缓冲区安全检查。
    15. /Zi:生成调试信息。
    16. /ZI:将调试信息包含在与“编辑并继续”兼容的程序数据库中。 (仅限 x86)大小的i
    17. /Z7:生成与 C 7.0 兼容的调试信息。
    18. /Zp:指定结构体成员的对齐方式。
    19. /Zl:禁用默认库名。小写的L
    20. /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文件包含了调试信息,用于在调试程序时提供更好的可读性和可用性。
    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链接器提供了丰富的选项,可以对程序进行定制化的链接,以满足不同的需求。

1.9 MSVC编译器链接器使用

  1. 在Visual Studio中,MSVC编译器、连接器参数全部是可视化配置,不需要像GCC一样编写命令行;

  2. 可对照官网的参数选项文档进行配置学习;

  3. 如果需要在Qt中配置MSVC编译器的参数,可以先在Visual Studio中通过可视化选项配置好再将对应的选项填入Qt的工程中;

  4. 如下图所示,再Visual Studio中打开工程的属性页,在属性页中可以选择C/C++编译器、链接器,然后进行参数的可视化配置。

    在这里插入图片描述

posted @ 2023-04-01 22:53  mahuifa  阅读(0)  评论(0编辑  收藏  举报  来源