【编译、链接、装载一】预处理、编译、汇编、链接

这篇具有很好参考价值的文章主要介绍了【编译、链接、装载一】预处理、编译、汇编、链接。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简介

对于平常的应用程序开发,我们很少需要关注编译和链接过程,因为通常的开发环境都是流行的集成开发环境(IDE),比如Visual Studio等。这样的IDE一般都将编译和链接的过程一步完成,通常将这种编译和链接合并到一起的过程称为构建(Build)。即使使用命令行来编译一个源代码文件,简单的一句“gcc hello.c”命令就包含了非常复杂的过程。

IDE和编译器提供的默认配置、编译和链接参数对于大部分的应用程序开发而言已经足够使用了。但是在这样的开发过程中,我们往往会被这些复杂的集成工具所提供的强大功能所迷惑,很多系统软件的运行机制与机理被掩盖,其程序的很多莫名其妙的错误让我们无所适从,面对程序运行时种种性能瓶颈我们束手无策。我们看到的是这些问题的现象,但是却很难看清本质,所有这些问题的本质就是软件运行背后的机理及支撑软件运行的各种平台和工具,如果能够深入了解这些机制,那么解决这些问题就能够游刃有余,收放自如了。

一、被隐藏了的过程

C语言的经典,“Hello World”程序。

使用c语言做例子吧,我使用cpp的预处理过,但是预处理的文件太长了。

#include <stdio.h>
int main()
{
printf("Hello World\n");
return 0;
}

在Linux下,当我们使用GCC来编译Hello World程序时,只须使用最简单的命令(源代码文件名为hello.c):

$gcc hello.c
$./a.out

Hello World事实上,上述过程可以分解为4个步骤,分别是预处理(Prepressing)、编译(Compilation)、汇编(Assembly)和链接(Linking),如图所示。
【编译、链接、装载一】预处理、编译、汇编、链接

二、预处理器(Prepressing)——cpp

  • 预处理有的文章中,也被称为预编译

1、预处理指令

  • 使用预处理器cpp
    会把.c文件预处理成一个.i文件。
$cpp hello.c > hello.i
  • 实战
    【编译、链接、装载一】预处理、编译、汇编、链接

2、预处理过程

预处理过程主要处理那些源代码文件中的以“#”开始的预编译指令。比如 “#include”、“#define ”等,主要处理规则如下:

  • 将所有的 “#define ”删除,并且展开所有的宏定义。
  • 处理所有条件预编译指令,比如 “#if”、“#ifdef”、“#elif”、“#else”、“#endif ”。
  • 处理 “#include ”预编译指令,将被包含的文件插入到该预编译指令的位置。注意,这个过程是递归进行的,也就是说被包含的文件可能还包含其他文件。
  • 删除所有的注释“//”和“/* */”。
  • 添加行号和文件名标识,比如#2“hello.c”2,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号。
  • 保留所有的 #pragma 编译器指令,因为编译器须要使用它们。

经过预编译后的.i文件不包含任何宏定义,因为所有的宏已经被展开,并且包含的文件也已经被插入到.i文件中。所以当我们无法判断宏定义是否正确或头文件包含是否正确时,可以查看预编译后的文件来确定问题。

3、预处理生成的hello.i文件

【编译、链接、装载一】预处理、编译、汇编、链接

三、编译器(Compilation)——cc

1、编译指令

编译过程就是把预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后生产相应的汇编代码文件,这个过程往往是我们所说的整个程序构建的核心部分,也是最复杂的部分之一。我们将在下一节简单介绍编译的具体几个步骤,这涉及编译原理等一些内容,由于它不是本书介绍的核心内容,所以也仅仅是介绍而已。

目前公司产品有用到这部分的内容,因为公司产品中有自己的语言。但是产品底层的词法分析和语法分析等部分不是我负责的。后面有机会的话继续深入的了解下。

上面的编译过程相当于如下命令:

$cc hello.i -S -o hello.s

可以得到汇编输出文件hello.s

2、编译的过程

  • 词法分析
  • 语法分析
  • 语义分析
  • 中间语言生成
  • 目标代码生成与优化

3、编译生成的文件(如下图)

后面分一篇文章,详细的介绍下以下的指令都是什么意思。
【编译、链接、装载一】预处理、编译、汇编、链接

四、汇编器(Assembly)——as

1、汇编指令

汇编器是将汇编代码转变成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令。所以汇编器的汇编过程相对于编译器来讲比较简单,它没有复杂的语法,也没有语义,也不需要做指令优化,只是根据汇编指令和机器指令的对照表一一翻译就可以了,“汇编”这个名字也来源于此。

  • 上面的汇编过程我们可以调用汇编器as来完成:
$as hello.s -o hello.o
  • 实战
    汇编生成的目标文件hello.o如下图所示
    【编译、链接、装载一】预处理、编译、汇编、链接

2、查看汇编生成的目标文件

$objdump -h hello.o

【编译、链接、装载一】预处理、编译、汇编、链接

五、链接器(Linking)——ld

1、链接器

  • 链接器是一个将编译器产生的目标文件打包成可执行文件或者库文件或者目标文件的程序。
    从这句话可以看出,链接器实际上是一个程序,它的输入是编译器产生的目标文件,输出是库、可执行文件或者其它目标文件。

目标文件:.so 文件生成.out文件

链接的指令

ld /usr/lib64/crt1.o /usr/lib64/crti.o /usr/lib64/crtn.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbeginT.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5 -L/usr/lib64 -L/usr/lib --start-group -lgcc -lgcc_eh -lc --end-group hello.o -o hello.out

或者

ld /usr/lib64/crt1.o /usr/lib64/crti.o /usr/lib64/crtn.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbeginT.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5 -L/usr/lib64 -L/usr/lib -lstdc++ -lm -lgcc_s -lc -lgcc hello.o -o hello.out

2、查看链接生成的程序

$objdump -h hello.out
  • 从下图可知,从汇编的6个,链接后变成了23个。

【编译、链接、装载一】预处理、编译、汇编、链接【编译、链接、装载一】预处理、编译、汇编、链接

六、执行hello.out

$./hello.out

【编译、链接、装载一】预处理、编译、汇编、链接

  • 执行报错bash: ./test.out: /lib/ld64.so.1: bad ELF interpreter: 没有那个文件或目录?

bash: ./test.out: /lib/ld64.so.1: bad ELF interpreter: 没有那个文件或目录

解决方案见:/lib/ld64.so.1: bad ELF interpreter: 没有那个文件或目录,因为这个问题不太好处理,所以单独分了一篇文章,记录下解决问题的过程。

七、gcc能做的事:预处理、编译、汇编、链接

上面预处理、编译、汇编、链接,我们分别使用了cpp、cc、as、ld。
其实,预处理、编译、汇编、链接这四个过程,gcc自己就能干完了。

  • 1、使用gcc预处理(-E表示只进行预编译)。
$gcc -E hello.c -o hello.i
  • 2、编译
$gcc -S hello.i -o hello.s

或者使用如下命令:

$gcc -S hello.c -o hello.s

  • 3、汇编
$gcc -c hello.s -o hello.o 

或者使用gcc命令从C源代码文件开始,经过预编译、编译和汇编直接输出目标文件(Object File):

$gcc -c hello.c -o hello.o

备注:
gcc -c hello.c -o hello.o小写的-c才是仅仅汇编,
gcc -C hello.c -o hello.o如果是大写的-C,会进行链接的。

  • 4、链接
$gcc hello.o -o hello.out
或者
$gcc hello.o -o hello
  • 5、执行
    【编译、链接、装载一】预处理、编译、汇编、链接
  • 5、查看gcc指令
[dev1@localhost test01]$ gcc --help
用法:gcc [选项] 文件...
选项:
  -pass-exit-codes         在某一阶段退出时返回最高的错误码
  --help                   显示此帮助说明
  --target-help            显示目标机器特定的命令行选项
  --help={common|optimizers|params|target|warnings|[^]{joined|separate|undocumented}}[,...]
                           显示特定类型的命令行选项
  (使用‘-v --help’显示子进程的命令行参数)
  --version                显示编译器版本信息
  -dumpspecs               显示所有内建 spec 字符串
  -dumpversion             显示编译器的版本号
  -dumpmachine             显示编译器的目标处理器
  -print-search-dirs       显示编译器的搜索路径
  -print-libgcc-file-name  显示编译器伴随库的名称
  -print-file-name=<库>    显示 <库> 的完整路径
  -print-prog-name=<程序>  显示编译器组件 <程序> 的完整路径
  -print-multiarch         Display the target's normalized GNU triplet, used as
                           a component in the library path
  -print-multi-directory   显示不同版本 libgcc 的根目录
  -print-multi-lib         显示命令行选项和多个版本库搜索路径间的映射
  -print-multi-os-directory 显示操作系统库的相对路径
  -print-sysroot           显示目标库目录
  -print-sysroot-headers-suffix 显示用于寻找头文件的 sysroot 后缀
  -Wa,<选项>               将逗号分隔的 <选项> 传递给汇编器
  -Wp,<选项>               将逗号分隔的 <选项> 传递给预处理器
  -Wl,<选项>               将逗号分隔的 <选项> 传递给链接器
  -Xassembler <参数>       将 <参数> 传递给汇编器
  -Xpreprocessor <参数>    将 <参数> 传递给预处理器
  -Xlinker <参数>          将 <参数> 传递给链接器
  -save-temps              不删除中间文件
  -save-temps=<arg>        不删除中间文件
  -no-canonical-prefixes   生成其他 gcc 组件的相对路径时不生成规范化的
                           前缀
  -pipe                    使用管道代替临时文件
  -time                    为每个子进程计时
  -specs=<文件>            用 <文件> 的内容覆盖内建的 specs 文件
  -std=<标准>              指定输入源文件遵循的标准
  --sysroot=<目录>         将 <目录> 作为头文件和库文件的根目录
  -B <目录>                将 <目录> 添加到编译器的搜索路径中
  -v                       显示编译器调用的程序
  -###                     与 -v 类似,但选项被引号括住,并且不执行命令
  -E                       仅作预处理,不进行编译、汇编和链接
  -S                       编译到汇编语言,不进行汇编和链接
  -c                       编译、汇编到目标代码,不进行链接
  -o <文件>                输出到 <文件>
  -pie                     Create a position independent executable
  -shared                  Create a shared library
  -x <语言>                指定其后输入文件的语言
                           允许的语言包括:c c++ assembler none
                           ‘none’意味着恢复默认行为,即根据文件的扩展名猜测
                           源文件的语言

以 -g、-f、-m、-O、-W 或 --param 开头的选项将由 gcc 自动传递给其调用的
 不同子进程。若要向这些进程传递其他选项,必须使用 -W<字母> 选项。

报告程序缺陷的步骤请参见:
<http://bugzilla.redhat.com/bugzilla>.

八、其他知识点

1、cc、cc1、ccl、gcc

1.1、cc

  • 一般的CC就是一个软件链接到GCC的。只不过CC是UNIX中常用的编译工具,而在linux中用的是GCC,有一些在UNIX中写好的程序要放在linux中要指定命令CC编译器,所以将CC指定为GCC。其实就是一个东西。
  • 从下图,我们可以看到,cc和gcc链接的库都一致,所以说他们是一个东西的说法是正确的,但是并不是cc链接了gcc.
    【编译、链接、装载一】预处理、编译、汇编、链接

1.2、cc1

cc1是windows系统下提供的编译器,安装MinGW后,再安装gcc可以就可以看到,作用同gcc.

linux下也有,在/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/cc1

【编译、链接、装载一】预处理、编译、汇编、链接

1.3、ccl

  • 很多书籍和文章都说链接器使用ccl,但是我们并找不到ccl的指令。(除非自己吧gcc改名为ccl例外)。
  • 能找到的和编译相关的cll,链接如下

a:
Compiling Directly via the CCL Compiler,从网站我们可以看到,其生成的目标文件是.ccx,而非.s文件。而从下文可以看到其名字叫做c8_compiler 。

This section describes the CCL compiler, and how to invoke it on different platforms.
The CCL compiler is a separate program, which can be invoked by the user.The name of the program is c8_compiler (or c8_compiler.exe on Microsoft Windows) //软件的名字叫c8_compiler

b:
CCL
https://github.com/Clozure/ccl

Because CCL is written in itself, you need an already-working version of CCL to compile it.

b这个ccl,虽然和语言相关,但是并非是c语言的编译器。

c:
https://www.researchgate.net/figure/CCL-compiler-and-interpreter_fig1_228539904

综上所述:很多书籍中提到的ccl编译命令是不存在的,正确的应该是cc1\cc\gcc。

1.4、gcc

GCC:全称GNU Compiler Collection,GNU编译器套装,是广泛应用的Linux系统的默认编译器(特别是用于编译Linux内核)。GCC能够支持多种架构的处理器,跨平台特性相对出色。不过,GNU组织要求全部的代码由自己完成(防止版权问题),所以GCC虽然有广泛的硬件支持,但是在各硬件平台上却并不是性能最优的编译器。

1.5、icc

ICC:全称Intel C++ Compiler,是Intel开发的C/C++/Fortran编译器套装,适用于Linux、Microsoft和Mac OS X操作系统,没有非IA指令集版本(就是说仅供x86架构CPU使用)。ICC广泛应用于高性能计算、分布式计算等商业计算领域,其向量化和并行化性能是业界的标杆,能够充分发挥现代处理器的特性。

2、cpp

参考:
Oracle_手册页部分_用户命令_用户命令cpp

  • 名称
    cpp - C 语言预处理程序
  • 用法概要
/usr/lib/cpp [-BCHMpPRT] [
-undef] [-Dname] [
-Dname = def] 
     [-Idirectory] [-U
name] [-Ydirectory] 
     [input-file [output-file]]
  • 描述
    cpp 是 C 语言预处理程序。cpp 还用作其他 Sun 编译器的第一遍操作的预处理程序。
    cpp 可以接受两个文件名作为参数。 input-file 和 output-file 分别是用于预处理程序的输入和输出文件。缺省情况下,它们是标准输入和标准输出。

3、gcc、g++

gcc和g++是什么,有什么区别?

发展至今(2020 年 6 月份),GCC 编译器已经更新至 10.1.0 版本,其功能也由最初仅能编译 C 语言,扩增至可以编译多种编程语言,其中就包括 C++ 。

除此之外,当下的 GCC 编译器还支持编译 Go、Objective-C,Objective-C ++,Fortran,Ada,D 和 BRIG(HSAIL)等程序,甚至于 GCC 6 以及之前的版本还支持编译 Java 程序。但本教程主要讲解如何使用 GCC 编译器编译运行 C 和 C++ 程序,因此有关其它编程语言如何使用 GCC 编译器编译,将不再做具体讲解。

那么,在已编辑好 C 语言或者 C++ 代码的前提下,如何才能调用 GCC 编译器为我们编译程序呢?很简单,GCC 编译器已经为我们提供了调用它的接口,对于 C 语言或者 C++ 程序,可以通过执行 gcc 或者 g++ 指令来调用 GCC 编译器。

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

那么,gcc 和 g++ 的区别是什么呢?接下来就给读者做详细的讲解。

实际上,只要是 GCC 支持编译的程序代码,都可以使用 gcc 命令完成编译。可以这样理解,gcc 是 GCC 编译器的通用编译指令,因为根据程序文件的后缀名,gcc 指令可以自行判断出当前程序所用编程语言的类别,比如:

  • xxx.c:默认以编译 C 语言程序的方式编译此文件;
  • xxx.cpp:默认以编译 C++ 程序的方式编译此文件。
  • xxx.m:默认以编译 Objective-C 程序的方式编译此文件;
  • xxx.go:默认以编译 Go 语言程序的方式编译此文件;

当然,gcc 指令也为用户提供了“手动指定代表编译方式”的接口,即使用 -x 选项。例如,gcc -xc xxx 表示以编译 C 语言代码的方式编译 xxx 文件;而 gcc -xc++ xxx 则表示以编译 C++ 代码的方式编译 xxx 文件。有关 -x 选项的用法,后续会给出具体样例。

但如果使用 g++ 指令,则无论目标文件的后缀名是什么,该指令都一律按照编译 C++ 代码的方式编译该文件。也就是说,对于 .c 文件来说,gcc 指令以 C 语言代码对待,而 g++ 指令会以 C++ 代码对待。但对于 .cpp 文件来说,gcc 和 g++ 都会以 C++ 代码的方式编译。

4、问chatGPT:c语言预处理、编译、汇编、链接这四个过程,在linux分别由哪些实现方式

chatGPT答复如下:

在Linux系统上,C语言预处理、编译、汇编和链接这四个过程可以使用以下工具实现:

  1. 预处理 - 可以使用GNU C Preprocessor (cpp)工具进行预处理。例如,在终端中输入以下命令来生成预处理后的代码:
   cpp hello.c > hello.i
  1. 编译 - 可以使用GCC(GNU Compiler Collection)或Clang等C语言编译器进行编译。例如,在终端中输入以下命令将预处理后的代码编译成目标文件:
   gcc -c hello.i -o hello.o
  1. 汇编 - 可以使用GNU Assembler (gas)或其他汇编器将编译后的目标文件转换为汇编代码。例如,在终端中输入以下命令将目标文件汇编成汇编代码:
   objdump -d hello.o > hello.s
  1. 链接 - 可以使用GNU Linker (ld)或其他链接器将多个目标文件连接成一个可执行文件。例如,在终端中输入以下命令将多个目标文件链接成可执行文件:
   gcc -o hello hello.o

请注意,不同的Linux系统可能会使用不同的工具和命令来进行C语言编译和开发。以上示例仅供参考,实际操作时应根据自己的需求和情况进行调整。

5、问chatGPT:c语言预处理生成的hello.i文件,除了使用gcc可以编译成hello.s文件,还有哪些方式可以编译成hello.s文件

除了使用GCC编译器,您可以使用其他C语言编译器或预处理工具来将预处理后的"hello.i"文件编译成汇编代码(".s"文件)。例如:

  1. Clang - Clang是另一个流行的开源C语言编译器,与GCC类似,可以将预处理后的C源文件编译成汇编代码。您可以使用以下命令生成汇编代码文件:

    clang -S hello.i

  2. LLVM IR - LLVM IR是一种中间表示形式,可以通过LLVM编译器将其转换为汇编代码。您可以使用以下命令将预处理后的C源文件编译为LLVM IR:

    clang -emit-llvm -S hello.i

    然后,您可以使用以下命令将LLVM IR编译为汇编代码:

    llc -march=x86-64 hello.ll -o hello.s

  3. CPP - 除了使用C语言编译器,您还可以使用预处理工具CPP将预处理后的C源文件转换为汇编代码。您可以使用以下命令生成汇编代码文件:

    cpp hello.i > hello.cpp
    g++ -S hello.cpp

请注意,不同的编译器和工具可能会产生不同的汇编代码,因此生成的".s"文件可能会有所不同。

参考
1、《程序员的自我修养链接装载与库》
2、深入理解计算机系统第七章 链接知识整理
3、C编译器翻译c程序的四个阶段
4、程序员C语言快速上手——工程篇(十二)
5、GCC命令 (预处理cpp --> 编译ccl --> 汇编as --> 链接ld)(转载)
6、GCC\LD文章来源地址https://www.toymoban.com/news/detail-466847.html

到了这里,关于【编译、链接、装载一】预处理、编译、汇编、链接的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 程序环境和预处理(含C语言程序的编译+链接)--2

    文章前言: 上章我们把      程序的翻译环境     程序的执行环境   C语言程序的编译+链接     预定义符号介绍    预处理指令   #define    宏和函数的对比     预处理操作符    #和##的介绍   的相关知识进行了梳理讲解,接下来被把剩余知识    命令定义     预处

    2024年02月14日
    浏览(51)
  • 【编译、链接、装载十六】汇编与指针、汇编与new

    简介:我们从预处理、编译、汇编、编译、链接、装载一路走到现在,一直在c语言的层面分析,原因还是这些知识太苦涩,理解时需要看下具体的反汇编代码,且c++的反汇编更难理解些,所以,c语言的入手比c++入手更简单和更好理解些。在这个系列的结尾,我们从汇编层面

    2024年02月13日
    浏览(41)
  • 编译预处理:#if

    #if expression … #elif … #end expression 是整数常量比较的表达式,例如: defined表达式,例如 defined AAA, 或者 defined(AAA), 如果AAA是一个宏定义,return true,否则,return false; 单个整数,例如:1/10/100/0, 非零为true,零为false; 整数比较,例如:1 == 1为true, 0 == 0为ture, 1 2为false; 单个

    2023年04月14日
    浏览(70)
  • 【C语言:编译、预处理详解】

    我们都知道,一个程序如果想运行起来要经过编译、链接然后才能生成.exe的文件。 编译⼜可以分解为三个过程: 预处理(有些书也叫预编译)、 编译 汇编 预处理阶段 主要处理那些源文件中以#开始的预编译指令。比如:#include,#define,处理的规则如下: 删除所有的注释

    2024年02月03日
    浏览(48)
  • 预处理/预编译详解(C/C++)

            在上一篇的bolg中的编译与链接中提到过 预处理 ,但只是较为简单的讲解,本篇将会对预处理进行详细的讲解。         其中在预处理中很重要的一个一个知识点是#define定义常量与宏,还区分了宏与函数的区别,以及#和##符号,还涉及条件编译头文件的包含等等。

    2024年01月17日
    浏览(48)
  • c语言中编译过程与预处理

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 在c语言的一个项目中会有很多.c文件,这些.c文件就是源文件,组成一个程序的每个源文件通过编译过程分别转换成目标代码(object code),即每个源文件都转换为对应的目标文件,即.obj文件。 然后这些

    2024年02月11日
    浏览(41)
  • 【C语言】从预处理到机器代码的C语言编译过程解析

    当我们编写一个C语言程序时,我们需要经历一个编译的过程,将源代码转换为可执行的机器代码。这个过程涉及到多个阶段和环节,每个阶段都有其特定的任务和功能。在本篇博客中,我们将详细介绍C语言的编译过程。 目录 一、预处理阶段(Preprocessing) 二、词法分析阶段

    2024年02月13日
    浏览(34)
  • 015+limou+C语言深入知识——(7)编译环境和运行环境以及预处理指令

    在这个环境中,源代码被转化为可执行的机器指令(二进制指令) 单文件简易版本 多文件简易版本 编译链接详细版本 VS2022集成IDE(windows下)的编译器叫cl.exe,链接器叫link.exe gcc编译器(windows下)的几个有关编译环境的命令 (1)符号表会把全局变量和具有外部链接的函数

    2023年04月11日
    浏览(38)
  • 预处理详解(#和##运算符、命名约定、#undef​​、命令行定义​、条件编译、头文件的包含​)

    目录 一、#和## 1.1#运算符 1.2## 运算符​ 二、命名约定​ 三、#undef​ 四、命令行定义​ 五、条件编译​ 六、头文件的包含​ 4.1 头文件被包含的方式:​ 4.1.1 本地文件包含​ Linux环境的标准头文件的路径:​ VS环境的标准头文件的路径: 4.1.2库文件包含​ 4.2嵌套文件包含

    2024年01月18日
    浏览(54)
  • 【ARM 嵌入式 编译系列 2.1 -- GCC 预处理命令 #error 和 #warning 详细介绍 】

    在C语言中, #error 和 #warning 预处理指令可以用于在编译时生成错误或警告信息,通常用于调试或当代码中某些条件未满足时提醒开发者。当这些指令被编译器处理时,会自动包含出现这些指令的文件名和行号,所以你可以清楚地看到问题出现的位置。 #error 当编译器遇到 #e

    2024年01月22日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包