<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>C/C++ on 云雾海的博客</title><link>https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/</link><description>Recent content in C/C++ on 云雾海的博客</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Sat, 11 Feb 2023 15:02:59 +0800</lastBuildDate><atom:link href="https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/index.xml" rel="self" type="application/rss+xml"/><item><title>C/C++ 声明和定义</title><link>https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/%E5%A3%B0%E6%98%8E%E5%92%8C%E5%AE%9A%E4%B9%89/</link><pubDate>Sat, 11 Feb 2023 15:02:59 +0800</pubDate><guid>https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/%E5%A3%B0%E6%98%8E%E5%92%8C%E5%AE%9A%E4%B9%89/</guid><description>&lt;img src="https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/%E5%A3%B0%E6%98%8E%E5%92%8C%E5%AE%9A%E4%B9%89/cover.jpg" alt="Featured image of post C/C++ 声明和定义" /&gt;&lt;!-- @import "[TOC]" {cmd="toc" depthFrom=1 depthTo=6 orderedList=false} --&gt;&#10;&lt;!-- code_chunk_output --&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e5%89%8d%e8%a8%80" &gt;前言&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e7%bc%96%e8%af%91%e5%92%8c%e9%93%be%e6%8e%a5" &gt;编译和链接&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e5%a3%b0%e6%98%8e%e5%92%8c%e5%ae%9a%e4%b9%89" &gt;声明和定义&lt;/a&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e8%a6%81%e5%a3%b0%e6%98%8e" &gt;为什么要声明&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e8%a6%81%e5%ae%9a%e4%b9%89" &gt;为什么要定义&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e6%80%bb%e7%bb%93" &gt;总结&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;!-- /code_chunk_output --&gt;&#10;&lt;h2 id="前言"&gt;&lt;a href="#%e5%89%8d%e8%a8%80" class="header-anchor"&gt;&lt;/a&gt;前言&#10;&lt;/h2&gt;&lt;p&gt;很多编程语言的语法中都有关于声明和定义的概念，这种概念一般会应用于函数或变量的创建和使用中，但是为什么要这么做？&lt;/p&gt;&#10;&lt;p&gt;以C语言为例，一些书籍或教程会要求读者在程序文件开头写上函数和变量的声明，然后再在后面对其进行定义（对于变量也可以叫初始化）。这不免让人感到有一丝疑惑，为什么要这样做？我能不能先定义再声明？或者我能否不声明直接定义？&lt;/p&gt;&#10;&lt;p&gt;事实上这样做很多时候也是可以的，但是为什么呢？&lt;/p&gt;&#10;&lt;p&gt;为此我们需要明确一些基本的概念。&lt;/p&gt;&#10;&lt;h2 id="编译和链接"&gt;&lt;a href="#%e7%bc%96%e8%af%91%e5%92%8c%e9%93%be%e6%8e%a5" class="header-anchor"&gt;&lt;/a&gt;编译和链接&#10;&lt;/h2&gt;&lt;p&gt;以C和C++为例，如果你正在使用某个IDE进行编程，那么你应该可以发现，在你写好一个程序后需要将它运行之前，往往需要先进行构建（有的IDE里面写的是生成或build），然后经过一段时间的等待后，你就会获得一个可执行程序，之后你就可以运行这个程序文件得到想要的效果。&lt;/p&gt;&#10;&lt;p&gt;这个过程中发生了什么呢？一般情况下这个过程分为了三步——预处理、编译、链接。预处理过程一般是C和C++的特色，你所见到的那些带&lt;code&gt;#&lt;/code&gt;的语句一般被称为宏，而这些宏将会被预处理器进行预处理。通常而言，你只需要知道&lt;code&gt;#define&lt;/code&gt;（将被定义的内容用定义的内容进行替换）和&lt;code&gt;#include&lt;/code&gt;（将被引用的文件全部原样复制到此）两个宏就够了。&lt;/p&gt;&#10;&lt;p&gt;不过预处理并不是我们讨论的焦点。&lt;/p&gt;&#10;&lt;p&gt;编译一般发生于预处理之后，一般而言，当预处理结束后，所有有用的&lt;code&gt;.h&lt;/code&gt;文件都已经通过&lt;code&gt;#include&lt;/code&gt;被原样复制到了&lt;code&gt;.c&lt;/code&gt;文件中了，所以整个工程现在就只剩下一堆&lt;code&gt;.c&lt;/code&gt;文件。而编译器会检测每个&lt;code&gt;.c&lt;/code&gt;文件然后将它们编译称为对应的汇编文件，再然后将汇编文件翻译成二进制文件。不过一般而言，翻译成为汇编文件这个过程都是被隐藏的，至少如果不单独设置你是无法看到生成汇编文件这个过程。不过没关系，这样也可以简化我们的思路，所以直接将编译过程理解为从&lt;code&gt;.c&lt;/code&gt;文件到二进制文件（这个文件后缀根据编译器和系统的不同可能有所差异，一般是&lt;code&gt;.o&lt;/code&gt;或&lt;code&gt;.obj&lt;/code&gt;，当然具体是什么后缀都不重要）。&lt;/p&gt;&#10;&lt;p&gt;编译结束后，显然我们会得到一堆二进制文件，它们和之前写的&lt;code&gt;.c&lt;/code&gt;文件一般是一一对应的。但是很显然，这些二进制文件还不是可执行程序，而且它们太分散了。这个时候就需要链接器进行工作，链接器会根据链接表将所有二进制文件进行重组和拼装，最后形成一个完整的可执行文件。&lt;/p&gt;&#10;&lt;h2 id="声明和定义"&gt;&lt;a href="#%e5%a3%b0%e6%98%8e%e5%92%8c%e5%ae%9a%e4%b9%89" class="header-anchor"&gt;&lt;/a&gt;声明和定义&#10;&lt;/h2&gt;&lt;p&gt;那么，声明和定义在这里有什么用呢？&lt;/p&gt;&#10;&lt;h3 id="为什么要声明"&gt;&lt;a href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e8%a6%81%e5%a3%b0%e6%98%8e" class="header-anchor"&gt;&lt;/a&gt;为什么要声明&#10;&lt;/h3&gt;&lt;p&gt;现在我们假设一个工程中有两个&lt;code&gt;.c&lt;/code&gt;文件，一个是&lt;code&gt;main.c&lt;/code&gt;，里面放了一个空的main函数，此外什么也没有。另一个是&lt;code&gt;hello.c&lt;/code&gt;，里面放了一个&lt;code&gt;void SayHello()&lt;/code&gt;函数并引用了&lt;code&gt;stdio.h&lt;/code&gt;文件，这个函数的功能是输出一个&lt;code&gt;Hello World&lt;/code&gt;。&lt;/p&gt;&#10;&lt;p&gt;显然，&lt;code&gt;hello.c&lt;/code&gt;里面实现了对&lt;code&gt;SayHello&lt;/code&gt;函数的定义，也就是说我们的工程中已经实现了&lt;code&gt;SayHello&lt;/code&gt;这个函数，此时我们是否能够在&lt;code&gt;main&lt;/code&gt;函数中调用它呢？&lt;/p&gt;&#10;&lt;p&gt;如果你尝试直接在&lt;code&gt;main&lt;/code&gt;函数中调用&lt;code&gt;SayHello&lt;/code&gt;，然后分别对&lt;code&gt;main.c&lt;/code&gt;和&lt;code&gt;hello.c&lt;/code&gt;进行编译（一般IDE会有单独的编译选项，右键单击某个c文件就可以选择，而且这个编译事实上还是包括了预处理过程的），你会发现对&lt;code&gt;main.c&lt;/code&gt;进行编译的时候会出现报错。&lt;/p&gt;&#10;&lt;p&gt;编译器会提示你，没有对&lt;code&gt;SayHello&lt;/code&gt;函数进行定义。&lt;/p&gt;&#10;&lt;p&gt;但是我们明明在&lt;code&gt;hello.c&lt;/code&gt;中进行定义了啊？难道是我需要先编译一下&lt;code&gt;hello.c&lt;/code&gt;然后再编译&lt;code&gt;main.c&lt;/code&gt;？事实上你换一下顺序结果也是一样。&lt;/p&gt;&#10;&lt;p&gt;因为编译器是没有记忆的，当他编译完一个文件，就会马上忘记它在这个文件里都发现了什么东西，所以哪怕它刚刚才在&lt;code&gt;hello.c&lt;/code&gt;里面编译了&lt;code&gt;SayHello&lt;/code&gt;的定义，但是现在它在编译&lt;code&gt;main.c&lt;/code&gt;，它就已经忘记了这回事了。&lt;/p&gt;&#10;&lt;p&gt;那么我们有什么办法可以解决这种情况呢？&lt;/p&gt;&#10;&lt;p&gt;第一种方法就是，在&lt;code&gt;main.c&lt;/code&gt;的前面加上对&lt;code&gt;SayHello&lt;/code&gt;的定义，注意尤其一定要在&lt;code&gt;main&lt;/code&gt;函数的前面。有人会问，为什么一定要在前面，后面不行吗？事实上确实不行，因为当编译器发现一个它从来没见过的函数调用时，就会马上报错，不会那么智能地再在后面找一遍你是不是定义在后面了，所以唯有在调用之前就定义好，他才知道你有好好定义这个函数，然后它就不会闹了。&lt;/p&gt;&#10;&lt;p&gt;但是显然，如果我希望在多个文件里面调用&lt;code&gt;SayHello&lt;/code&gt;函数，那么这个方法就不起效了。&lt;/p&gt;&#10;&lt;p&gt;所以我们就有了第二种方法，在&lt;code&gt;main.c&lt;/code&gt;文件前面加上一句对&lt;code&gt;SayHello&lt;/code&gt;的声明。声明只需要写上函数返回值、函数名和函数参数表就可以了，不需要写完整的实现。声明其实是程序员对编译器的保证，意思就是“我保证我在其它某个地方肯定会写这个函数的定义的”，然后编译器会相信程序员，虽然你并没有实际在这个文件中定义这个函数，但是当你调用这个函数的时候，编译器不会报错。注意，声明也需要写在调用的前面，逻辑和第一种方法一样。&lt;/p&gt;&#10;&lt;p&gt;现在你大概理解了声明的意思了，而一般情况下，声明会被写在一个&lt;code&gt;.h&lt;/code&gt;文件中，要使用某个函数之前只要&lt;code&gt;#include&lt;/code&gt;这个文件并且将它对应的&lt;code&gt;.c&lt;/code&gt;文件包含在工程内即可。&lt;/p&gt;&#10;&lt;p&gt;注意，除了&lt;code&gt;#include&lt;/code&gt;，你一定也要将它对应的&lt;code&gt;.c&lt;/code&gt;文件包含在工程内，因为&lt;code&gt;.c&lt;/code&gt;文件里包含了对这些函数的定义。&lt;/p&gt;&#10;&lt;h3 id="为什么要定义"&gt;&lt;a href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e8%a6%81%e5%ae%9a%e4%b9%89" class="header-anchor"&gt;&lt;/a&gt;为什么要定义&#10;&lt;/h3&gt;&lt;p&gt;没有定义显然是不行的，否则这个函数就是一个空有名字和输入输出的不明物，很显然这是程序员的疏忽（或像我们故意）造成的错误，是需要被发现检测出来的。&lt;/p&gt;&#10;&lt;p&gt;现在，我们做个简单的小实验，还是刚才的工程，但是我们将&lt;code&gt;hello.c&lt;/code&gt;里的&lt;code&gt;SayHello&lt;/code&gt;注释掉（如果你不怕麻烦想要更好的体验，可以直接删掉&lt;code&gt;hello.c&lt;/code&gt;或将它移出工程），此时我们再次编译&lt;code&gt;hello.c&lt;/code&gt;和&lt;code&gt;main.c&lt;/code&gt;，你会发现，编译器仍然没有报错。&lt;/p&gt;&#10;&lt;p&gt;是不是有点疑惑，现在明显没有&lt;code&gt;SayHello&lt;/code&gt;的定义，但是为什么编译器不报错呢？&lt;/p&gt;&#10;&lt;p&gt;很显然，是因为编译器非常相信你，你在&lt;code&gt;main.c&lt;/code&gt;中声明了，你一定会定义&lt;code&gt;SayHello&lt;/code&gt;的，所以编译器就理所当然地相信了你，而没有记忆的它显然是无法发现自己被骗了。而&lt;code&gt;hello.c&lt;/code&gt;文件里什么都没有，那么自然也不会有什么错（如果你直接将其移除了工程就更加不可能报错了）。&lt;/p&gt;&#10;&lt;p&gt;但是这并不代表你能一直骗它，我们知道编译结束后还得链接才能得到可执行程序，不过IDE一般没有单独的链接按钮，所以我们得使用构建，当按下这个按钮后整个工程都将完整经历完前面说的三个过程——预处理、编译和链接。其中预处理和编译仍然是刚才我们的编译器进行的，它和刚才一样，没有发现任何问题。&lt;/p&gt;&#10;&lt;p&gt;但是你骗不了链接器，因为它会对程序进行重新组装，但是在组装的过程中它会发现，有一个本来应该出现的函数定义却在此刻不见了，然后它会发出一个&lt;code&gt;L&lt;/code&gt;字母开头的报错，唯有你在工程中重新创建了这个函数的定义并重新构建才可以消除。&lt;/p&gt;&#10;&lt;h2 id="总结"&gt;&lt;a href="#%e6%80%bb%e7%bb%93" class="header-anchor"&gt;&lt;/a&gt;总结&#10;&lt;/h2&gt;&lt;p&gt;这里用C语言的函数声明与定义解释了为什么要声明和定义以及它们有什么用，用相同的逻辑它也可以扩展到变量以及其它语言的声明与定义中。&lt;/p&gt;&#10;</description></item><item><title>STM32CubeMX GCC工程Makefile内容详解</title><link>https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/stm32cubemx-gcc%E5%B7%A5%E7%A8%8Bmakefile%E5%86%85%E5%AE%B9%E8%AF%A6%E8%A7%A3/</link><pubDate>Tue, 08 Mar 2022 00:30:45 +0800</pubDate><guid>https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/stm32cubemx-gcc%E5%B7%A5%E7%A8%8Bmakefile%E5%86%85%E5%AE%B9%E8%AF%A6%E8%A7%A3/</guid><description>&lt;img src="https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/stm32cubemx-gcc%E5%B7%A5%E7%A8%8Bmakefile%E5%86%85%E5%AE%B9%E8%AF%A6%E8%A7%A3/cover.jpg" alt="Featured image of post STM32CubeMX GCC工程Makefile内容详解" /&gt;&lt;h1 id="stm32cubemx-gcc工程makefile内容详解"&gt;&lt;a href="#stm32cubemx-gcc%e5%b7%a5%e7%a8%8bmakefile%e5%86%85%e5%ae%b9%e8%af%a6%e8%a7%a3" class="header-anchor"&gt;&lt;/a&gt;STM32CubeMX GCC工程Makefile内容详解&#10;&lt;/h1&gt;&lt;!-- @import "[TOC]" {cmd="toc" depthFrom=1 depthTo=6 orderedList=false} --&gt;&#10;&lt;!-- code_chunk_output --&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="#stm32cubemx-gcc%e5%b7%a5%e7%a8%8bmakefile%e5%86%85%e5%ae%b9%e8%af%a6%e8%a7%a3" &gt;STM32CubeMX GCC工程Makefile内容详解&lt;/a&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e5%9f%ba%e7%a1%80%e4%bb%8b%e7%bb%8d" &gt;基础介绍&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e6%b3%a8%e6%84%8f" &gt;注意&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#makefile" &gt;Makefile&lt;/a&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="#target" &gt;TARGET&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#debug" &gt;DEBUG&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#opt" &gt;OPT&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#build_dir" &gt;BUILD_DIR&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#c_sources" &gt;C_SOURCES&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#asm_sources" &gt;ASM_SOURCES&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#prefix" &gt;PREFIX&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#ccascpsz" &gt;CC,AS,CP,SZ&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#hexbin" &gt;HEX,BIN&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#cpu" &gt;CPU&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#fpu" &gt;FPU&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#float-abi" &gt;FLOAT-ABI&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#mcu" &gt;MCU&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#ad_defsc_defs" &gt;AD_DEFS,C_DEFS&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#as_includesc_includes" &gt;AS_INCLUDES,C_INCLUDES&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#asflagscflags" &gt;ASFLAGS,CFLAGS&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#ifeq-debug-1" &gt;ifeq ($(DEBUG), 1)&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#cflags" &gt;CFLAGS&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#ldscripts" &gt;LDSCRIPTS&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#libslibdir" &gt;LIBS,LIBDIR&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#ldflags" &gt;LDFLAGS&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#all" &gt;all&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#objects" &gt;OBJECTS&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#build" &gt;BUILD&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#clean" &gt;clean&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#flash" &gt;flash&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#dependencies" &gt;dependencies&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e7%bb%93%e8%af%ad" &gt;结语&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;!-- /code_chunk_output --&gt;&#10;&lt;h2 id="基础介绍"&gt;&lt;a href="#%e5%9f%ba%e7%a1%80%e4%bb%8b%e7%bb%8d" class="header-anchor"&gt;&lt;/a&gt;基础介绍&#10;&lt;/h2&gt;&lt;p&gt;因为项目原因，需要对编译系统进行一些比较复杂的使用，但是我对于编译系统这一块并不是非常精通了解，所以需要进行一下学习。正巧，众所周知STM32推出过非常实用的工具——STM32CubeMX，这个工具可以对STM32进行一些基础配置并设置一些配置代码，基本可以靠图形界面完成对STM32的所有初始化配置，然后它就会生成一个基础工程，编程者在这个基础上进行设置即可。&lt;/p&gt;&#10;&lt;p&gt;当然，本文主要关注点是在编译系统，所以该工具的配置什么的就不详细说了，基本上就是简单随便配置一下时钟就可以了（事实上应该时钟都不需要配置），重点在于我们生成工程的时候需要选择生成Makefile工程，这样才可以使用我们的开源工具链进行配置。&lt;/p&gt;&#10;&lt;p&gt;之后我们可以得到如下的工程目录（当然，众所周知CubeMX的一些设置会影响到工程根目录的具体结构，不过这都不是重点）：&lt;/p&gt;&#10;&lt;img class="gallery-image" data-flex-basis="149px" data-flex-grow="62" height="320" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/stm32cubemx-gcc%E5%B7%A5%E7%A8%8Bmakefile%E5%86%85%E5%AE%B9%E8%AF%A6%E8%A7%A3/img/6938647bafeaacf0a1a8963e69dd68a0.webp" width="199"&gt;&lt;p&gt;其中build目录是编译后生成的，先不管，另外Core文件夹下的Test文件夹及其中内容是我进行测试的时候添加的，暂时也先不管。&lt;/p&gt;&#10;&lt;p&gt;我们先来看看其它的东西，首先是Core中的内容，这部分的内容基本上就完全是STM32CubeMX生成的，Inc中放h文件而Src中放c文件，里面的文件都是在CubeMX中配置过的东西，这些东西是每次CubeMX在修改后都会重新生成的东西（也有可能是你修改了哪一部分，就会重新生成哪一部分的文件，这个是CubeMX自己的机制，不重要）。&lt;/p&gt;&#10;&lt;p&gt;其次是Drivers中的内容，这些内容实际上都是从 CubeMX的安装目录里的sdk中复制过来的，如果我们在配置的时候没有选择要将这些东西复制过来，那么CubeMX也不会生成这个目录下的内容（或者不能说生成，而就是直接复制过来），但是取而代之的就是你使用的所有sdk的库函数，都是直接调用的安装目录里的东西，那么为了安全性着想，就不要在编程的时候修改他们了，否则你的库函数就被你的代码污染了，当然这样做的好处就是你的代码复用性会提高而且工程体积会稍微小点。&lt;/p&gt;&#10;&lt;p&gt;然后是下面的&lt;code&gt;.mxproject&lt;/code&gt;文件，CubeMX的工程文件，不管。&lt;/p&gt;&#10;&lt;p&gt;接着就是我们等会最重要的Makefile，这个是Make工具的脚本文件，如果你不知道Make工具是啥，建议先了解一下再看本文会好一点。&lt;/p&gt;&#10;&lt;p&gt;之后是&lt;code&gt;MakeTest.ioc&lt;/code&gt;文件，CubeMX的配置文件，不管。&lt;/p&gt;&#10;&lt;p&gt;然后是后缀为s的start文件，这个文件是芯片的项目启动文件，一般不需要管，里面放了中断向量表之类的东西。&lt;/p&gt;&#10;&lt;p&gt;最后是后缀为ld的链接脚本文件，这个是用于链接的，等会会说。&lt;/p&gt;&#10;&lt;h2 id="注意"&gt;&lt;a href="#%e6%b3%a8%e6%84%8f" class="header-anchor"&gt;&lt;/a&gt;注意&#10;&lt;/h2&gt;&lt;p&gt;本文的解析结构并没有按照makefile的解析顺序来，而是采用从上到下的顺序来解说的（当然会根据实际情况进行跳跃），主要原因在于我学习这个东西的目的主要是直接把这个Makefile当成一个模板，然后未来直接在这个模板上进行修改就可以了，而到目前为止我暂时还不打算自己从头来写个Makefile（毕竟能用就行，平时哪需要那么麻烦）。&lt;/p&gt;&#10;&lt;p&gt;考虑到篇幅，就不单独把全部makefile列出来了，需要时你直接用CubeMX生成一个工程然后看它Makefile即可，只要STM32公司那边没有对这个规则进行大改，那么下面这些内容应该都大差不差。&lt;/p&gt;&#10;&lt;p&gt;此外，本文中很多东西其实可以在&lt;a class="link" href="https://gcc.gnu.org/onlinedocs/" target="_blank" rel="noopener"&#10; &gt;gcc的手册&lt;/a&gt;中找到答案，如果感兴趣可以去看看。&lt;/p&gt;&#10;&lt;h2 id="makefile"&gt;&lt;a href="#makefile" class="header-anchor"&gt;&lt;/a&gt;Makefile&#10;&lt;/h2&gt;&lt;h3 id="target"&gt;&lt;a href="#target" class="header-anchor"&gt;&lt;/a&gt;TARGET&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;TARGET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; MakeTest&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;设置目标文件名，实际上就是做了个变量，并且把Makefile这个作为参数传入。平时当成工程名即可，如果要换工程，就自己随便重新取个名字。&lt;/p&gt;&#10;&lt;h3 id="debug"&gt;&lt;a href="#debug" class="header-anchor"&gt;&lt;/a&gt;DEBUG&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;DEBUG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;是否进行调试编译，这里表示是，release版关闭调试时将1改成其它数即可，具体原因后面会讲到。&lt;/p&gt;&#10;&lt;h3 id="opt"&gt;&lt;a href="#opt" class="header-anchor"&gt;&lt;/a&gt;OPT&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;OPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; -Og&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;优化等级，这里使用Og的目的是因为开启了调试，所以优化时需要产生合理的优化而不和调试选项冲突。如果是release版本，可以使用&lt;code&gt;-Os&lt;/code&gt;（提高速度并优化体积）或&lt;code&gt;-O3&lt;/code&gt;（大幅提高速度但会增大体积）等命令，关于这部分的介绍可以参考&lt;a class="link" href="https://www.zhihu.com/question/27090458/answer/137944410" target="_blank" rel="noopener"&#10; &gt;知乎回答&lt;/a&gt;。&lt;/p&gt;&#10;&lt;h3 id="build_dir"&gt;&lt;a href="#build_dir" class="header-anchor"&gt;&lt;/a&gt;BUILD_DIR&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;BUILD_DIR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; build&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编译目标地址，这也是前面提到为什么我会生成一个build文件夹，实际上就是这个变量进行的命名，如果你需要，可以把它修改成任何名字，然后编译出来的所有文件就都会放在这个你新命名的文件夹里面了。不过一般不建议修改，因为大家通用的都是build，不建议太特立独行。&lt;/p&gt;&#10;&lt;h3 id="c_sources"&gt;&lt;a href="#c_sources" class="header-anchor"&gt;&lt;/a&gt;C_SOURCES&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;C_SOURCES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Core/Src/main.c &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Core/Src/gpio.c &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Core/Src/usart.c &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Core/Src/stm32f4xx_it.c &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Core/Src/stm32f4xx_hal_msp.c &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Core/Test/test.c&lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc_ex.c &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash.c &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ex.c &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ramfunc.c &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma_ex.c &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr.c &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr_ex.c &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_exti.c &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Core/Src/system_stm32f4xx.c&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其实从名字我们不难理解，这里放的就是所有用到的c文件。如果我们需要自己写个什么库自己写了什么新的c文件，而且最后会被编译到程序里面的话，就都需要自己在这里添加一行c文件地址。这些地址可以是相对路径，相对的就是makefile文件的地址，而如果不好相对路径，那么也可以设置为绝对路径，例如这里面所有Drivers的文件，如果我们没有配置为复制到工程里面，那么这些文件就会被写为绝对路径并导航到你的CubeMX的sdk存储地址里面。&lt;/p&gt;&#10;&lt;p&gt;此外，注意我添加了一行test.c的路径，这一行就是我自己写的文件，里面定义了一个全局变量，并被对应的test.h使用extern引用，然后在Src文件夹下面被main.c引用test.h后使用。这里我想说明的是，哪怕你用h文件做了个跳板（而不是直接extern过来）然后调用了test.c的东西，而且test.c中连个函数都没有，但是只要你使用了里面的东西，就必须要把文件地址填在上面的文件列表中。&lt;/p&gt;&#10;&lt;p&gt;不过说实话我个人感觉这样做非常麻烦，这里我有点想知道为什么不能直接添加一个文件夹然后遍历下面的所有c文件并添加呢？为此我还稍微查询了一下，找到了这个博客《&lt;a class="link" href="https://blog.csdn.net/qq849635649/article/details/52935079" target="_blank" rel="noopener"&#10; &gt;一点一点学写Makefile(6)-遍历当前目录源文件及其子目录下源文件&lt;/a&gt;》，感兴趣可以看看。&lt;/p&gt;&#10;&lt;h3 id="asm_sources"&gt;&lt;a href="#asm_sources" class="header-anchor"&gt;&lt;/a&gt;ASM_SOURCES&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ASM_SOURCES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;startup_stm32f411xe.s&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;所有汇编文件的地址，添加方法可以继续参考前面C文件的添加方法，也是绝对地址和相对地址添加即可。而这里的start文件，一般不需要用户自己写，这些厂商在开发好芯片后都至少会提供一个startup的c或s文件的，我们需要做的就只是把他添加进来即可（有的可能不是汇编s文件，如果是c文件，正常添加到前面C文件的路径下面即可，这种情况下汇编这里就不需要添加startup了，不过此外你自己写的其他汇编文件倒是仍然可以正常这样写进去）。&lt;/p&gt;&#10;&lt;h3 id="prefix"&gt;&lt;a href="#prefix" class="header-anchor"&gt;&lt;/a&gt;PREFIX&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;PREFIX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; arm-none-eabi-&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;工具链起始名，说白了就是你使用的开源工具链（当然你有钱也可以买闭源的，不过没啥必要而且使用起来需要再自行研究一下），这里变量的内容是arm-none-eabi-，其实这个是一个gcc工具链的名字，这个工具链全程一般叫&lt;code&gt;arm-none-eabi-gcc&lt;/code&gt;，arm表示架构平台，none表示无系统，eabi表示嵌入式应用二进制接口，gcc表示其遵守的GNU GCC的设计规范。这东西我记得之前在哪个很古老的博客上面看到的，但是当时忘了收藏，所以现在找不到了。总之，开发者将这个工具链除gcc部分命名后，里面的所有工具就全部使用这个前缀了，这个东西我们在后面会说。&lt;/p&gt;&#10;&lt;p&gt;如果你需要对linux的arm设备进行开发，那么你可能需要安装arm-linux-eabi-gcc（当然也可能是其他名字或顺序，这个是开发者自己决定的，因为里面还可以添加开发者名称，所以好像没有非常严格的规范），如果你需要对riscv架构的设备进行开发，那么可能需要使用riscv-none-gcc，总之，需要什么自己去芯片官网上先看看有没有推荐，然后下载并改这里的参数即可。&lt;/p&gt;&#10;&lt;h3 id="ccascpsz"&gt;&lt;a href="#ccascpsz" class="header-anchor"&gt;&lt;/a&gt;CC,AS,CP,SZ&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;ifdef&lt;/span&gt; &lt;span class="err"&gt;GCC_PATH&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;CC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;GCC_PATH&lt;span class="k"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;$(&lt;/span&gt;PREFIX&lt;span class="k"&gt;)&lt;/span&gt;gcc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;GCC_PATH&lt;span class="k"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;$(&lt;/span&gt;PREFIX&lt;span class="k"&gt;)&lt;/span&gt;gcc -x assembler-with-cpp&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;CP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;GCC_PATH&lt;span class="k"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;$(&lt;/span&gt;PREFIX&lt;span class="k"&gt;)&lt;/span&gt;objcopy&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;SZ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;GCC_PATH&lt;span class="k"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;$(&lt;/span&gt;PREFIX&lt;span class="k"&gt;)&lt;/span&gt;size&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;else&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;CC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;PREFIX&lt;span class="k"&gt;)&lt;/span&gt;gcc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;PREFIX&lt;span class="k"&gt;)&lt;/span&gt;gcc -x assembler-with-cpp&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;CP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;PREFIX&lt;span class="k"&gt;)&lt;/span&gt;objcopy&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;SZ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;PREFIX&lt;span class="k"&gt;)&lt;/span&gt;size&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;endif&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里我们需要分别看两个东西，其中是ifdef部分，这东西是一个判断你有没有定义某个变量，看名字大概也可以猜到，这个就是我们gcc工具链的地址。这就涉及到一个问题，也就是环境变量，如果你将你的工具链的工具目录地址添加到环境变量中，那么我们就可以在命令行中直接通过工具的名称调用这个工具，否则我们就需要输入绝对路径来调用工具。&lt;/p&gt;&#10;&lt;p&gt;比如你的arm-none-eabi-gcc存储在D盘根目录下，那么你很可能需要在环境变量中添加&lt;code&gt;D:\arm-none-eabi-gcc\bin\&lt;/code&gt;文件夹地址，此时我们就可以在命令行中直接使用&lt;code&gt;arm-none-eabi-gcc&lt;/code&gt;来运行&lt;code&gt;D:\arm-none-eabi-gcc\bin\arm-none-eabi-gcc.exe&lt;/code&gt;程序，否则，我们就需要输入完整的绝对路径来调用该程序。&lt;/p&gt;&#10;&lt;p&gt;而GCC_PATH就是用来帮助你添加这个绝对路径的，如果你没有添加环境变量，那么就可以在makefile前面定义GCC_PATH并添加上地址，如&lt;code&gt;D:\arm-none-eabi-gcc\bin&lt;/code&gt;，那么之后我们会运行ifdef中的程序（如果没定义就直接使用后面else的程序），makefile所有变量的本质其实就是字符替换，此时例如CC，就会被编译为&lt;code&gt;D:\arm-none-eabi-gcc\bin\arm-none-eabi-gcc.exe&lt;/code&gt;，其余同理。当然，如果你不想在makefile中添加这个变量，也可以选择在输入&lt;code&gt;make&lt;/code&gt;指令的时候添加&lt;code&gt;GCC_PATH=D:\arm-none-eabi-gcc\bin&lt;/code&gt;。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;PREFIX&lt;/code&gt;前面也已经说过了，不赘述。&lt;/p&gt;&#10;&lt;p&gt;然后我们关注到这四个工具，其中gcc出现了两次，分别在CC和AS中，CC中直接使用gcc，其实代表了其默认参数编译C语言，而AS从名字在可以猜是代表了汇编器，其使用了-x参数表示更换编译语言，只不过代表所更换的参数assembler-with-cpp，似乎不只是可以汇编，还可以处理C++？不过我把test.c改名成test.cpp后分别添加到汇编和C的Sources列表中似乎都不行，会编译错误，有点不是很懂，不过总之其可以编译汇编语言成为机器语言是肯定的。&lt;/p&gt;&#10;&lt;p&gt;之后是CP的objcopy，这是个复制文件内容的工具，具体介绍可以参考《&lt;a class="link" href="https://my.oschina.net/dake/blog/196707" target="_blank" rel="noopener"&#10; &gt;objcopy命令介绍 - Dake的信息摘录博客&lt;/a&gt;》。&lt;/p&gt;&#10;&lt;p&gt;SZ是一个记录生成程序内部各分段的大小的工具，这个在编译后查看编译出的文件大小进行项目优化的时候会比较有用，makefile中也用了这个工具，在编译到最后会输出这样的内容：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;arm-none-eabi-size build/MakeTest.elf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; text data bss dec hex filename&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="m"&gt;6524&lt;/span&gt; &lt;span class="m"&gt;24&lt;/span&gt; &lt;span class="m"&gt;1640&lt;/span&gt; &lt;span class="m"&gt;8188&lt;/span&gt; 1ffc build/MakeTest.elf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;值得注意的是这个size工具只能对elf文件进行解析，而hex和bin文件中是不包含代码段数据段这些东西的。这里的大概意思是我的代码段有6524字节，数据段有24字节，bss段有1640字节，总共加起来有8188字节。关于这些段的介绍，参考可以参考这个博客《&lt;a class="link" href="https://blog.csdn.net/zhy557/article/details/80832268" target="_blank" rel="noopener"&#10; &gt;堆栈、BSS段、代码段、数据段、RO、RW、ZI等概念区分&lt;/a&gt;》。&lt;/p&gt;&#10;&lt;h3 id="hexbin"&gt;&lt;a href="#hexbin" class="header-anchor"&gt;&lt;/a&gt;HEX,BIN&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;HEX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;CP&lt;span class="k"&gt;)&lt;/span&gt; -O ihex&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;BIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;CP&lt;span class="k"&gt;)&lt;/span&gt; -O binary -S&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从名字我们就不难看出，这里其实指的就是生成十六进制文件和二进制文件，他们都是可以被烧录到stm32中的代码文件格式，而其中的参数也很好懂，分别就是生成十六进制和二进制所需的参数，没啥好解释的，直接用就行。&lt;/p&gt;&#10;&lt;h3 id="cpu"&gt;&lt;a href="#cpu" class="header-anchor"&gt;&lt;/a&gt;CPU&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;CPU&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; -mcpu&lt;span class="o"&gt;=&lt;/span&gt;cortex-m4&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;选择cpu的架构，因为我使用的是stm32f4的芯片，故这里的架构是cortex-m4，如果是其它架构需要进行修改。&lt;/p&gt;&#10;&lt;h3 id="fpu"&gt;&lt;a href="#fpu" class="header-anchor"&gt;&lt;/a&gt;FPU&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;FPU&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; -mfpu&lt;span class="o"&gt;=&lt;/span&gt;fpv4-sp-d16&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;选择fpu的架构，这里是因为F4系列有fpu，所以可以添加，如果没有就需要关闭，关闭后无法使用fpu对浮点数计算进行加速，相关概念可以参考《&lt;a class="link" href="https://blog.csdn.net/weixin_42415539/article/details/110139722" target="_blank" rel="noopener"&#10; &gt;【arm-gcc开发STM32】开启stm32f4的FPU&lt;/a&gt;》。&lt;/p&gt;&#10;&lt;h3 id="float-abi"&gt;&lt;a href="#float-abi" class="header-anchor"&gt;&lt;/a&gt;FLOAT-ABI&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;FLOAT-ABI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; -mfloat-abi&lt;span class="o"&gt;=&lt;/span&gt;hard&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;硬浮点或软浮点，如果有FPU就可以开启硬浮点，这里开启了，相关概念可以参考《&lt;a class="link" href="http://blog.chinaunix.net/uid-27875-id-5785166.html" target="_blank" rel="noopener"&#10; &gt;浮点 _ 运算处理方式(软硬-mfloat-abi=) _ 浮点协处理器类型 -mfpu=&lt;/a&gt;》。&lt;/p&gt;&#10;&lt;h3 id="mcu"&gt;&lt;a href="#mcu" class="header-anchor"&gt;&lt;/a&gt;MCU&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;MCU&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;CPU&lt;span class="k"&gt;)&lt;/span&gt; -mthumb &lt;span class="k"&gt;$(&lt;/span&gt;FPU&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;FLOAT-ABI&lt;span class="k"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;此处代表了所有针对MCU硬件的配置，其它的我们已经说过，而这个&lt;code&gt;-mthumb&lt;/code&gt;代表的是T32指令集，如果使用了另外一种指令集的架构就需要换这里的参数，具体参考《&lt;a class="link" href="http://blog.sina.com.cn/s/blog_675a80790102ylnk.html" target="_blank" rel="noopener"&#10; &gt;【解读经典】ARM体系结构与编程（3）&lt;/a&gt;》。&lt;/p&gt;&#10;&lt;h3 id="ad_defsc_defs"&gt;&lt;a href="#ad_defsc_defs" class="header-anchor"&gt;&lt;/a&gt;AD_DEFS,C_DEFS&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;AS_DEFS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;C_DEFS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-DUSE_HAL_DRIVER &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;-DSTM32F411xE&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;分别是汇编和C的宏定义，这个项目中的汇编里面因为不需要，所以啥也没写，如果你不需要在汇编程序中增加什么外部的宏定义，就不需要这个。&lt;/p&gt;&#10;&lt;p&gt;而C文件宏定义，真正的宏需要去掉每个宏定义开头的-D，例如此处的-DUSE_HAL_DRIVER，实际上是宏定义了USE_HAL_DRIVER，这些宏定义会影响到c文件里面相关宏的内容，例如这个HAL，其实就代表了HAL库，那么C文件里面引用的东西就会选择HAL库而非LL库的内容。如果你想的话，也可以自己添加一些宏定义在c文件中作为开关，然后在这里添加东西表示打开。&lt;/p&gt;&#10;&lt;h3 id="as_includesc_includes"&gt;&lt;a href="#as_includesc_includes" class="header-anchor"&gt;&lt;/a&gt;AS_INCLUDES,C_INCLUDES&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;AS_INCLUDES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;C_INCLUDES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-ICore/Inc &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-IDrivers/STM32F4xx_HAL_Driver/Inc &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-IDrivers/STM32F4xx_HAL_Driver/Inc/Legacy &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-IDrivers/CMSIS/Device/ST/STM32F4xx/Include &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;-IDrivers/CMSIS/Include&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;汇编和C的引用文件所在文件夹，其中因为汇编没有引用外部文件，所以什么也没有，如果有需要自己添加。&lt;/p&gt;&#10;&lt;p&gt;注意这里添加的是文件夹地址而不是具体的文件地址。&lt;/p&gt;&#10;&lt;p&gt;对于C来说，如果在自己的代码#include中使用了相对地址或绝对地址，则可以不添加，如果是只写了引用文件名或非本文件的文件名，则需要添加，以辅助编译器找到对应文件，编译器会主动从上述路径作为相对路径寻找include的文件。这里-I也全部是前缀。&lt;/p&gt;&#10;&lt;p&gt;例如我们需要在&lt;code&gt;Core\Src\main.c&lt;/code&gt;中引用&lt;code&gt;Core\Test\test.h&lt;/code&gt;，那么我们需要在main.c中写&lt;code&gt;#include &amp;quot;test.h&amp;quot;&lt;/code&gt;并在&lt;code&gt;C_INCLUDES&lt;/code&gt;中添加&lt;code&gt;-ICore/Test&lt;/code&gt;，而如果我们不在&lt;code&gt;C_INCLUDES&lt;/code&gt;中进行添加，那么main.c中就必须写相对或绝对地址，例如&lt;code&gt;#include &amp;quot;../Test/test.h&amp;quot;&lt;/code&gt;，这样才能保证我们的编译器能够找准位置。&lt;/p&gt;&#10;&lt;h3 id="asflagscflags"&gt;&lt;a href="#asflagscflags" class="header-anchor"&gt;&lt;/a&gt;ASFLAGS,CFLAGS&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ASFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;MCU&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;AS_DEFS&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;AS_INCLUDES&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;OPT&lt;span class="k"&gt;)&lt;/span&gt; -Wall -fdata-sections -ffunction-sections&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;MCU&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;C_DEFS&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;C_INCLUDES&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;OPT&lt;span class="k"&gt;)&lt;/span&gt; -Wall -fdata-sections -ffunction-sections&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编译参数，分别针对汇编和C语言，他们各自前面四个变量参数已经讲过，不再赘述。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;-Wall&lt;/code&gt;的功能主要是开启一些警告检测，如果我们的代码出现了不规范的地方，那么通过这个参数，编译器就会检查到这些地方并告知我们。关于这个参数的具体介绍可以参考《&lt;a class="link" href="http://blog.sina.com.cn/s/blog_553230d70101efqv.html" target="_blank" rel="noopener"&#10; &gt;gcc -Wall详解&lt;/a&gt;》。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;-fdata-sections&lt;/code&gt;表示对程序中每个数据创建一个section，而&lt;code&gt;-ffunction-sections&lt;/code&gt;则是针对函数创建section，GCC的链接操作是以section作为最小的处理单元，只要一个section中的某个符号被引用，该section就会被加到可执行程序中。关于这个部分具体可以参考《&lt;a class="link" href="https://blog.csdn.net/pengfei240/article/details/55228228" target="_blank" rel="noopener"&#10; &gt;gcc -ffunction-sections -fdata-sections -Wl,–gc-sections 参数详解&lt;/a&gt;》&lt;/p&gt;&#10;&lt;h3 id="ifeq-debug-1"&gt;&lt;a href="#ifeq-debug-1" class="header-anchor"&gt;&lt;/a&gt;ifeq ($(DEBUG), 1)&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;ifeq&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;DEBUG&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="err"&gt;1)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; -g -gdwarf-2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;endif&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;语句很好理解，如果DEBUG=1，就执行，如果不是1，就不执行。很显然，这段话就是检测目前是否是调试模式，而注意这里CFLAGS前面其实已经出现过，而这里再次出现时使用的就不再是等号=了，而是+=符号，这个符号在makefile中表示在已有变量后面补上新的符号。&lt;/p&gt;&#10;&lt;p&gt;而补上的其实就是两个新的参数，我们应该不难猜测这两个参数就是针对的调试生成的。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;-g&lt;/code&gt;表示的意思是生成调试信息，如果不生成的话我们在使用gdb调试的时候就很难做到代码定位，当然如果你不使用gdb，还可以使用&lt;code&gt;-gformat&lt;/code&gt;然后加上你想要的格式。而&lt;code&gt;-gdwarf-2&lt;/code&gt;的意思是生成DWARF version2 的格式的调试信息，常用于IRIXX6上的DBX调试器。GCC会使用DWARF version3的一些特性。关于这两个参数的使用，可以参考《&lt;a class="link" href="https://blog.csdn.net/luguifang2011/article/details/80642692" target="_blank" rel="noopener"&#10; &gt;GCC 编译及编译选项&lt;/a&gt;》。&lt;/p&gt;&#10;&lt;h3 id="cflags"&gt;&lt;a href="#cflags" class="header-anchor"&gt;&lt;/a&gt;CFLAGS&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; -MMD -MP -MF&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;@:%.o&lt;span class="o"&gt;=&lt;/span&gt;%.d&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;关于这个部分的内容又是针对CFLAGS，这里出现了三个新的参数，同时后面有一串makefile语法的宏。&lt;/p&gt;&#10;&lt;p&gt;这一串东西的主要功能是生成关联信息，关联信息会对链接产生影响，其中&lt;code&gt;-MMD&lt;/code&gt;表示会把关联信息输出到.d文件中，&lt;code&gt;-MF&lt;/code&gt;是指定用于存放关联信息的文件，&lt;code&gt;-MP&lt;/code&gt;生成的依赖文件里面，依赖规则中的所有 .h 依赖项都会在该文件中生成一个伪目标，其不依赖任何其他依赖项。该伪规则将避免删除了对应的头文件而没有更新 “Makefile” 去匹配新的依赖关系而导致 make 出错的情况出现。&lt;/p&gt;&#10;&lt;p&gt;关于这三个参数以及相关信息的介绍可以参考《&lt;a class="link" href="https://blog.csdn.net/linuxandroidwince/article/details/75221300" target="_blank" rel="noopener"&#10; &gt;GCC -M,-MM,-MMD,-MF,-MT&lt;/a&gt;》和《&lt;a class="link" href="https://blog.csdn.net/QQ1452008/article/details/50855810" target="_blank" rel="noopener"&#10; &gt;Linux Makefile 生成 *.d 依赖文件以及 gcc -M -MF -MP 等相关选项说明&lt;/a&gt;》。&lt;/p&gt;&#10;&lt;p&gt;而后面那一堆宏，说实话我也不太看得懂，毕竟我对Makefile的语法研究不深，不过看样子意思大概是针对MF的，而且大概含义是把所有o文件的名字复制生成对应的d文件，然后配合前面的参数，把关联信息生成到这些d文件中，而且通过build中的确d文件和o文件基本可以对应上，也侧面应证了这个猜想。&lt;/p&gt;&#10;&lt;h3 id="ldscripts"&gt;&lt;a href="#ldscripts" class="header-anchor"&gt;&lt;/a&gt;LDSCRIPTS&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;LDSCRIPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; STM32F411CEUx_FLASH.ld&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;链接脚本，里面包括了链接时各程序的组织架构，以及包括堆栈地址大小等信息，这个东西是CubeMX生成的，所以里面其实很多东西你在CubeMX中都可以修改。这里的内容不只是修改芯片，只要修改了了中断向量、堆栈大小等信息，均需要修改此部分，它其实就代表了你的程序在芯片的ROM中是怎么存储的，感兴趣可以自行查看一下这个文件，我把我的这个文件复制上来给各位看一下（删除了一些无用的注释）：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;/* Entry Point */&#10;ENTRY(Reset_Handler)&#10;&#10;/* Highest address of the user mode stack */&#10;_estack = 0x20020000; /* end of RAM */&#10;/* Generate a link error if heap and stack don&amp;#39;t fit into RAM */&#10;_Min_Heap_Size = 0x200; /* required amount of heap */&#10;_Min_Stack_Size = 0x400; /* required amount of stack */&#10;&#10;/* Specify the memory areas */&#10;MEMORY&#10;{&#10;RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K&#10;FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 512K&#10;}&#10;&#10;/* Define output sections */&#10;SECTIONS&#10;{&#10; /* The startup code goes first into FLASH */&#10; .isr_vector :&#10; {&#10; . = ALIGN(4);&#10; KEEP(*(.isr_vector)) /* Startup code */&#10; . = ALIGN(4);&#10; } &amp;gt;FLASH&#10;&#10; /* The program code and other data goes into FLASH */&#10; .text :&#10; {&#10; . = ALIGN(4);&#10; *(.text) /* .text sections (code) */&#10; *(.text*) /* .text* sections (code) */&#10; *(.glue_7) /* glue arm to thumb code */&#10; *(.glue_7t) /* glue thumb to arm code */&#10; *(.eh_frame)&#10;&#10; KEEP (*(.init))&#10; KEEP (*(.fini))&#10;&#10; . = ALIGN(4);&#10; _etext = .; /* define a global symbols at end of code */&#10; } &amp;gt;FLASH&#10;&#10; /* Constant data goes into FLASH */&#10; .rodata :&#10; {&#10; . = ALIGN(4);&#10; *(.rodata) /* .rodata sections (constants, strings, etc.) */&#10; *(.rodata*) /* .rodata* sections (constants, strings, etc.) */&#10; . = ALIGN(4);&#10; } &amp;gt;FLASH&#10;&#10; .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } &amp;gt;FLASH&#10; .ARM : {&#10; __exidx_start = .;&#10; *(.ARM.exidx*)&#10; __exidx_end = .;&#10; } &amp;gt;FLASH&#10;&#10; .preinit_array :&#10; {&#10; PROVIDE_HIDDEN (__preinit_array_start = .);&#10; KEEP (*(.preinit_array*))&#10; PROVIDE_HIDDEN (__preinit_array_end = .);&#10; } &amp;gt;FLASH&#10; .init_array :&#10; {&#10; PROVIDE_HIDDEN (__init_array_start = .);&#10; KEEP (*(SORT(.init_array.*)))&#10; KEEP (*(.init_array*))&#10; PROVIDE_HIDDEN (__init_array_end = .);&#10; } &amp;gt;FLASH&#10; .fini_array :&#10; {&#10; PROVIDE_HIDDEN (__fini_array_start = .);&#10; KEEP (*(SORT(.fini_array.*)))&#10; KEEP (*(.fini_array*))&#10; PROVIDE_HIDDEN (__fini_array_end = .);&#10; } &amp;gt;FLASH&#10;&#10; /* used by the startup to initialize data */&#10; _sidata = LOADADDR(.data);&#10;&#10; /* Initialized data sections goes into RAM, load LMA copy after code */&#10; .data : &#10; {&#10; . = ALIGN(4);&#10; _sdata = .; /* create a global symbol at data start */&#10; *(.data) /* .data sections */&#10; *(.data*) /* .data* sections */&#10;&#10; . = ALIGN(4);&#10; _edata = .; /* define a global symbol at data end */&#10; } &amp;gt;RAM AT&amp;gt; FLASH&#10;&#10; &#10; /* Uninitialized data section */&#10; . = ALIGN(4);&#10; .bss :&#10; {&#10; /* This is used by the startup in order to initialize the .bss secion */&#10; _sbss = .; /* define a global symbol at bss start */&#10; __bss_start__ = _sbss;&#10; *(.bss)&#10; *(.bss*)&#10; *(COMMON)&#10;&#10; . = ALIGN(4);&#10; _ebss = .; /* define a global symbol at bss end */&#10; __bss_end__ = _ebss;&#10; } &amp;gt;RAM&#10;&#10; /* User_heap_stack section, used to check that there is enough RAM left */&#10; ._user_heap_stack :&#10; {&#10; . = ALIGN(8);&#10; PROVIDE ( end = . );&#10; PROVIDE ( _end = . );&#10; . = . + _Min_Heap_Size;&#10; . = . + _Min_Stack_Size;&#10; . = ALIGN(8);&#10; } &amp;gt;RAM&#10;&#10; &#10;&#10; /* Remove information from the standard libraries */&#10; /DISCARD/ :&#10; {&#10; libc.a ( * )&#10; libm.a ( * )&#10; libgcc.a ( * )&#10; }&#10;&#10; .ARM.attributes 0 : { *(.ARM.attributes) }&#10;}&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我们简单看一下，最开始有个&lt;code&gt;ENTRY&lt;/code&gt;指令，里面参数是&lt;code&gt;Reset_Handler&lt;/code&gt;，显然它指向了一个所谓的复位句柄，那么这个句柄是在哪里呢？对，就是在我们前面说的startup汇编文件中，也就是说我们的入口程序实际上就是针对的这个句柄，然后后面通过这个句柄开始的程序进行逐渐执行，初始化硬件向量表这些，再然后才是开始运行我们的main程序，如果你需要写一些什么Bootloader之类的东西，其实也就是在这里看和改。&lt;/p&gt;&#10;&lt;p&gt;之后我们再继续查看后面的东西，可以发现我们还标注了RAM的大小、堆栈大小、地址等信息，这些信息都会最终被编译到我们的程序中，并且配合我们的烧录器或仿真器被烧录的芯片中的指定位置。&lt;/p&gt;&#10;&lt;p&gt;再之后就是每个区段section了，这些是对你的程序存储的划分，一般情况下我们是不需要对这些东西进行修改的，因为大部分芯片程序的运行存储理念都是差不多的，所以普通情况下我们需要修改的东西基本上就是前面的那些（当然，如果你换了其它芯片的架构，那可能还是要好好研究一下的）。&lt;/p&gt;&#10;&lt;h3 id="libslibdir"&gt;&lt;a href="#libslibdir" class="header-anchor"&gt;&lt;/a&gt;LIBS,LIBDIR&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;LIBS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; -lc -lm -lnosys&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;LIBDIR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;LIBS里面的这几个东西，代表的链接库，其实就是C语言的标准库，比如说这个-lm就代表了链接了标准数学库，不过具体这几个库链接的都是哪几个，我就不是很清楚了，具体可能要参考GCC的手册，但是我感觉没啥必要，毕竟都是标准库，链接了就链接了呗。除非你需要自己添加引用一些其他的链接库或者你需要缩减代码体积的时候，到时候再去研究哪个有用哪个没用就是了。&lt;/p&gt;&#10;&lt;p&gt;而对于LIBDIR，很明显也是一个库地址的意思，如果你使用的是非标准库需要从外面引用的话，就需要在这里添加东西了，添加的方法和前面添加c和汇编库的方法类似。&lt;/p&gt;&#10;&lt;h3 id="ldflags"&gt;&lt;a href="#ldflags" class="header-anchor"&gt;&lt;/a&gt;LDFLAGS&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;LDFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;MCU&lt;span class="k"&gt;)&lt;/span&gt; -specs&lt;span class="o"&gt;=&lt;/span&gt;nano.specs -T&lt;span class="k"&gt;$(&lt;/span&gt;LDSCRIPT&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;LIBDIR&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;LIBS&lt;span class="k"&gt;)&lt;/span&gt; -Wl,-Map&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;BUILD_DIR&lt;span class="k"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;$(&lt;/span&gt;TARGET&lt;span class="k"&gt;)&lt;/span&gt;.map,--cref -Wl,--gc-sections&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个就是链接的参数。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;-specs=nano.specs&lt;/code&gt;替换精简c库以缩小代码大小。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;-T&lt;/code&gt;使用脚本文件xxx作为链接器脚本，此脚本替换ld的默认链接脚本（而非加进去），因此命令文件必须给出所有输出文件所需的东西，这里的链接脚本我们在前面已经说过了。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;-Wl&lt;/code&gt;如果链接器不是直接被使用的，而是被编译器使用（如gcc），则所有的链接命令前面必须加上-Wl参数（或其他特殊编译器对应的参数）。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;-MAP&lt;/code&gt;打印一个链接表到map文件中。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;--cref&lt;/code&gt;输出一个交叉引用表。如果一个链接映射文件正在被生成，交叉参照表将会被输出到映射文件中。否则，将会被输出到标准输出。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;--gc-sections&lt;/code&gt;允许对未使用的段使用垃圾收集。在不支持这个选项的目标上将被自动忽略。默认的行为可用’–no-gc-sections’恢复。&lt;/p&gt;&#10;&lt;p&gt;关于这部分的内容可以参考《&lt;a class="link" href="https://blog.csdn.net/yyww322/article/details/50827683" target="_blank" rel="noopener"&#10; &gt;LD说明文档&amp;ndash;2.LD命令行命令翻译&lt;/a&gt;》&lt;/p&gt;&#10;&lt;h3 id="all"&gt;&lt;a href="#all" class="header-anchor"&gt;&lt;/a&gt;all&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;BUILD_DIR&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;TARGET&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;.&lt;span class="n"&gt;elf&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;BUILD_DIR&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;TARGET&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;.&lt;span class="n"&gt;hex&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;BUILD_DIR&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;TARGET&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;.&lt;span class="n"&gt;bin&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;默认执行全部编译，生成elf、hex和bin文件，文件地址和文件名在前面已经说过了。&lt;/p&gt;&#10;&lt;h3 id="objects"&gt;&lt;a href="#objects" class="header-anchor"&gt;&lt;/a&gt;OBJECTS&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;OBJECTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;addprefix &lt;span class="k"&gt;$(&lt;/span&gt;BUILD_DIR&lt;span class="k"&gt;)&lt;/span&gt;/,&lt;span class="k"&gt;$(&lt;/span&gt;notdir &lt;span class="k"&gt;$(&lt;/span&gt;C_SOURCES:.c&lt;span class="o"&gt;=&lt;/span&gt;.o&lt;span class="k"&gt;)))&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;vpath&lt;/span&gt; &lt;span class="err"&gt;%.c&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;sort&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;dir&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;C_SOURCES&lt;/span&gt;&lt;span class="k"&gt;)))&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;OBJECTS&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;addprefix &lt;span class="k"&gt;$(&lt;/span&gt;BUILD_DIR&lt;span class="k"&gt;)&lt;/span&gt;/,&lt;span class="k"&gt;$(&lt;/span&gt;notdir &lt;span class="k"&gt;$(&lt;/span&gt;ASM_SOURCES:.s&lt;span class="o"&gt;=&lt;/span&gt;.o&lt;span class="k"&gt;)))&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;vpath&lt;/span&gt; &lt;span class="err"&gt;%.s&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;sort&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;dir&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;ASM_SOURCES&lt;/span&gt;&lt;span class="k"&gt;)))&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这一大段都是makefile的语法，本质上代表了文件替换和名称命名等功能，一般而言我们修改芯片工程或其它什么时候，都不需要修改这个地方。该部分内容较多，另有博客对这一部分进行了比较详细的解释《&lt;a class="link" href="https://blog.csdn.net/qwe5959798/article/details/112367495" target="_blank" rel="noopener"&#10; &gt;(GCC)STM32CubeMX生成的Makefile详解&lt;/a&gt;》。&lt;/p&gt;&#10;&lt;h3 id="build"&gt;&lt;a href="#build" class="header-anchor"&gt;&lt;/a&gt;BUILD&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;$(BUILD_DIR)/%.o&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; %.&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;Makefile&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;BUILD_DIR&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;$(&lt;/span&gt;CC&lt;span class="k"&gt;)&lt;/span&gt; -c &lt;span class="k"&gt;$(&lt;/span&gt;CFLAGS&lt;span class="k"&gt;)&lt;/span&gt; -Wa,-a,-ad,-alms&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;BUILD_DIR&lt;span class="k"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;$(&lt;/span&gt;notdir &lt;span class="k"&gt;$(&lt;/span&gt;&amp;lt;:.c&lt;span class="o"&gt;=&lt;/span&gt;.lst&lt;span class="k"&gt;))&lt;/span&gt; $&amp;lt; -o &lt;span class="nv"&gt;$@&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;$(BUILD_DIR)/%.o&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; %.&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;Makefile&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;BUILD_DIR&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;$(&lt;/span&gt;AS&lt;span class="k"&gt;)&lt;/span&gt; -c &lt;span class="k"&gt;$(&lt;/span&gt;CFLAGS&lt;span class="k"&gt;)&lt;/span&gt; $&amp;lt; -o &lt;span class="nv"&gt;$@&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;$(BUILD_DIR)/$(TARGET).elf&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;OBJECTS&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Makefile&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;$(&lt;/span&gt;CC&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;OBJECTS&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;LDFLAGS&lt;span class="k"&gt;)&lt;/span&gt; -o &lt;span class="nv"&gt;$@&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;$(&lt;/span&gt;SZ&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$@&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;$(BUILD_DIR)/%.hex&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;BUILD_DIR&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;/%.&lt;span class="n"&gt;elf&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;BUILD_DIR&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;$(&lt;/span&gt;HEX&lt;span class="k"&gt;)&lt;/span&gt; $&amp;lt; &lt;span class="nv"&gt;$@&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;$(BUILD_DIR)/%.bin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;BUILD_DIR&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;/%.&lt;span class="n"&gt;elf&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;BUILD_DIR&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;$(&lt;/span&gt;BIN&lt;span class="k"&gt;)&lt;/span&gt; $&amp;lt; &lt;span class="nv"&gt;$@&lt;/span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;$(BUILD_DIR)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;mkdir &lt;span class="nv"&gt;$@&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这一部分实际上前面那个博客也介绍得差不多了，但是他没有讲到里面的几个参数的功能。&lt;/p&gt;&#10;&lt;p&gt;其中-c和-o这两个gcc最基础的参数就不说了，重点是第一部分中出现的&lt;code&gt;-Wa,-a,-ad,-alms&lt;/code&gt;几个参数是什么意思。说实话，我最开始也没找到，翻了gcc的手册但是只找到关于Wa的一点描述，而且还不咋看得懂。但是解铃还须系铃人，我们想要知道这几个意思其实最好的办法就是去问一下STM32，然后我就去STM32的官方论坛问了一下，对方给出了答复，说明这几个参数其实就是针对GCC的汇编器的，主要功能是生成一些信息还有引用一些库之类的，一般情况下我们对其可以不做更改。关于这里的问答，可以&lt;a class="link" href="https://community.st.com/s/feed/0D53W00001PXCcxSAH" target="_blank" rel="noopener"&#10; &gt;跳转到论坛界面进行查看&lt;/a&gt;。&lt;/p&gt;&#10;&lt;h3 id="clean"&gt;&lt;a href="#clean" class="header-anchor"&gt;&lt;/a&gt;clean&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;rm -fR &lt;span class="k"&gt;$(&lt;/span&gt;BUILD_DIR&lt;span class="k"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个东西没啥好说的，就是清除编译出来的那一大堆文件，一般情况下写makefile都需要这个东西防止生成东西太多影响空间，使用方法就是&lt;code&gt;make clean&lt;/code&gt;。&lt;/p&gt;&#10;&lt;h3 id="flash"&gt;&lt;a href="#flash" class="header-anchor"&gt;&lt;/a&gt;flash&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;flash&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;openocd -f interface/cmsis-dap.cfg -f target/stm32f4x.cfg -c &lt;span class="s2"&gt;&amp;#34;program &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;BUILD_DIR&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;TARGET&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;.elf reset exit&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;烧录程序，这个东西是我自己添加的，需要使用openocd并且配置环境变量，如果没有配置环境变量需要修改一下openocd命令的路径，而如果没有下载openocd的就无法使用这个功能了，这个功能不是必须的，如果需要可以直接使用stm32官方提供的烧录工具。&lt;/p&gt;&#10;&lt;h3 id="dependencies"&gt;&lt;a href="#dependencies" class="header-anchor"&gt;&lt;/a&gt;dependencies&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;-include&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;wildcard&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;BUILD_DIR&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;/*.&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;依赖引用，这里引用就是前面我们生成的关联文件，这些东西有什么用呢，其实目的就是为了生成我们的o文件。如果你看不懂这个东西什么意思，那么我们随便打开一个d文件其实你应该就懂了（如果你看过一点makefile基础）：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;build/gpio.o&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Core&lt;/span&gt;/&lt;span class="n"&gt;Src&lt;/span&gt;/&lt;span class="n"&gt;gpio&lt;/span&gt;.&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;Core&lt;/span&gt;/&lt;span class="n"&gt;Inc&lt;/span&gt;/&lt;span class="n"&gt;gpio&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="n"&gt;Core&lt;/span&gt;/&lt;span class="n"&gt;Inc&lt;/span&gt;/&lt;span class="n"&gt;main&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;STM&lt;/span&gt;32&lt;span class="n"&gt;F&lt;/span&gt;4&lt;span class="n"&gt;xx_HAL_Driver&lt;/span&gt;/&lt;span class="n"&gt;Inc&lt;/span&gt;/&lt;span class="n"&gt;stm&lt;/span&gt;32&lt;span class="n"&gt;f&lt;/span&gt;4&lt;span class="n"&gt;xx_hal&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Core&lt;/span&gt;/&lt;span class="n"&gt;Inc&lt;/span&gt;/&lt;span class="n"&gt;stm&lt;/span&gt;32&lt;span class="n"&gt;f&lt;/span&gt;4&lt;span class="n"&gt;xx_hal_conf&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;STM&lt;/span&gt;32&lt;span class="n"&gt;F&lt;/span&gt;4&lt;span class="n"&gt;xx_HAL_Driver&lt;/span&gt;/&lt;span class="n"&gt;Inc&lt;/span&gt;/&lt;span class="n"&gt;stm&lt;/span&gt;32&lt;span class="n"&gt;f&lt;/span&gt;4&lt;span class="n"&gt;xx_hal_rcc&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;STM&lt;/span&gt;32&lt;span class="n"&gt;F&lt;/span&gt;4&lt;span class="n"&gt;xx_HAL_Driver&lt;/span&gt;/&lt;span class="n"&gt;Inc&lt;/span&gt;/&lt;span class="n"&gt;stm&lt;/span&gt;32&lt;span class="n"&gt;f&lt;/span&gt;4&lt;span class="n"&gt;xx_hal_def&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;CMSIS&lt;/span&gt;/&lt;span class="n"&gt;Device&lt;/span&gt;/&lt;span class="n"&gt;ST&lt;/span&gt;/&lt;span class="n"&gt;STM&lt;/span&gt;32&lt;span class="n"&gt;F&lt;/span&gt;4&lt;span class="n"&gt;xx&lt;/span&gt;/&lt;span class="n"&gt;Include&lt;/span&gt;/&lt;span class="n"&gt;stm&lt;/span&gt;32&lt;span class="n"&gt;f&lt;/span&gt;4&lt;span class="n"&gt;xx&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;CMSIS&lt;/span&gt;/&lt;span class="n"&gt;Device&lt;/span&gt;/&lt;span class="n"&gt;ST&lt;/span&gt;/&lt;span class="n"&gt;STM&lt;/span&gt;32&lt;span class="n"&gt;F&lt;/span&gt;4&lt;span class="n"&gt;xx&lt;/span&gt;/&lt;span class="n"&gt;Include&lt;/span&gt;/&lt;span class="n"&gt;stm&lt;/span&gt;32&lt;span class="n"&gt;f&lt;/span&gt;411&lt;span class="n"&gt;xe&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;CMSIS&lt;/span&gt;/&lt;span class="n"&gt;Include&lt;/span&gt;/&lt;span class="n"&gt;core_cm&lt;/span&gt;4.&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;CMSIS&lt;/span&gt;/&lt;span class="n"&gt;Include&lt;/span&gt;/&lt;span class="n"&gt;cmsis_version&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;CMSIS&lt;/span&gt;/&lt;span class="n"&gt;Include&lt;/span&gt;/&lt;span class="n"&gt;cmsis_compiler&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;CMSIS&lt;/span&gt;/&lt;span class="n"&gt;Include&lt;/span&gt;/&lt;span class="n"&gt;cmsis_gcc&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;CMSIS&lt;/span&gt;/&lt;span class="n"&gt;Include&lt;/span&gt;/&lt;span class="n"&gt;mpu_armv&lt;/span&gt;7.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;CMSIS&lt;/span&gt;/&lt;span class="n"&gt;Device&lt;/span&gt;/&lt;span class="n"&gt;ST&lt;/span&gt;/&lt;span class="n"&gt;STM&lt;/span&gt;32&lt;span class="n"&gt;F&lt;/span&gt;4&lt;span class="n"&gt;xx&lt;/span&gt;/&lt;span class="n"&gt;Include&lt;/span&gt;/&lt;span class="n"&gt;system_stm&lt;/span&gt;32&lt;span class="n"&gt;f&lt;/span&gt;4&lt;span class="n"&gt;xx&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;STM&lt;/span&gt;32&lt;span class="n"&gt;F&lt;/span&gt;4&lt;span class="n"&gt;xx_HAL_Driver&lt;/span&gt;/&lt;span class="n"&gt;Inc&lt;/span&gt;/&lt;span class="n"&gt;Legacy&lt;/span&gt;/&lt;span class="n"&gt;stm&lt;/span&gt;32&lt;span class="n"&gt;_hal_legacy&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;STM&lt;/span&gt;32&lt;span class="n"&gt;F&lt;/span&gt;4&lt;span class="n"&gt;xx_HAL_Driver&lt;/span&gt;/&lt;span class="n"&gt;Inc&lt;/span&gt;/&lt;span class="n"&gt;stm&lt;/span&gt;32&lt;span class="n"&gt;f&lt;/span&gt;4&lt;span class="n"&gt;xx_hal_rcc_ex&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;STM&lt;/span&gt;32&lt;span class="n"&gt;F&lt;/span&gt;4&lt;span class="n"&gt;xx_HAL_Driver&lt;/span&gt;/&lt;span class="n"&gt;Inc&lt;/span&gt;/&lt;span class="n"&gt;stm&lt;/span&gt;32&lt;span class="n"&gt;f&lt;/span&gt;4&lt;span class="n"&gt;xx_hal_gpio&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;STM&lt;/span&gt;32&lt;span class="n"&gt;F&lt;/span&gt;4&lt;span class="n"&gt;xx_HAL_Driver&lt;/span&gt;/&lt;span class="n"&gt;Inc&lt;/span&gt;/&lt;span class="n"&gt;stm&lt;/span&gt;32&lt;span class="n"&gt;f&lt;/span&gt;4&lt;span class="n"&gt;xx_hal_gpio_ex&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;STM&lt;/span&gt;32&lt;span class="n"&gt;F&lt;/span&gt;4&lt;span class="n"&gt;xx_HAL_Driver&lt;/span&gt;/&lt;span class="n"&gt;Inc&lt;/span&gt;/&lt;span class="n"&gt;stm&lt;/span&gt;32&lt;span class="n"&gt;f&lt;/span&gt;4&lt;span class="n"&gt;xx_hal_exti&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;STM&lt;/span&gt;32&lt;span class="n"&gt;F&lt;/span&gt;4&lt;span class="n"&gt;xx_HAL_Driver&lt;/span&gt;/&lt;span class="n"&gt;Inc&lt;/span&gt;/&lt;span class="n"&gt;stm&lt;/span&gt;32&lt;span class="n"&gt;f&lt;/span&gt;4&lt;span class="n"&gt;xx_hal_dma&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;STM&lt;/span&gt;32&lt;span class="n"&gt;F&lt;/span&gt;4&lt;span class="n"&gt;xx_HAL_Driver&lt;/span&gt;/&lt;span class="n"&gt;Inc&lt;/span&gt;/&lt;span class="n"&gt;stm&lt;/span&gt;32&lt;span class="n"&gt;f&lt;/span&gt;4&lt;span class="n"&gt;xx_hal_dma_ex&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;STM&lt;/span&gt;32&lt;span class="n"&gt;F&lt;/span&gt;4&lt;span class="n"&gt;xx_HAL_Driver&lt;/span&gt;/&lt;span class="n"&gt;Inc&lt;/span&gt;/&lt;span class="n"&gt;stm&lt;/span&gt;32&lt;span class="n"&gt;f&lt;/span&gt;4&lt;span class="n"&gt;xx_hal_cortex&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;STM&lt;/span&gt;32&lt;span class="n"&gt;F&lt;/span&gt;4&lt;span class="n"&gt;xx_HAL_Driver&lt;/span&gt;/&lt;span class="n"&gt;Inc&lt;/span&gt;/&lt;span class="n"&gt;stm&lt;/span&gt;32&lt;span class="n"&gt;f&lt;/span&gt;4&lt;span class="n"&gt;xx_hal_flash&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;STM&lt;/span&gt;32&lt;span class="n"&gt;F&lt;/span&gt;4&lt;span class="n"&gt;xx_HAL_Driver&lt;/span&gt;/&lt;span class="n"&gt;Inc&lt;/span&gt;/&lt;span class="n"&gt;stm&lt;/span&gt;32&lt;span class="n"&gt;f&lt;/span&gt;4&lt;span class="n"&gt;xx_hal_flash_ex&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;STM&lt;/span&gt;32&lt;span class="n"&gt;F&lt;/span&gt;4&lt;span class="n"&gt;xx_HAL_Driver&lt;/span&gt;/&lt;span class="n"&gt;Inc&lt;/span&gt;/&lt;span class="n"&gt;stm&lt;/span&gt;32&lt;span class="n"&gt;f&lt;/span&gt;4&lt;span class="n"&gt;xx_hal_flash_ramfunc&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;STM&lt;/span&gt;32&lt;span class="n"&gt;F&lt;/span&gt;4&lt;span class="n"&gt;xx_HAL_Driver&lt;/span&gt;/&lt;span class="n"&gt;Inc&lt;/span&gt;/&lt;span class="n"&gt;stm&lt;/span&gt;32&lt;span class="n"&gt;f&lt;/span&gt;4&lt;span class="n"&gt;xx_hal_pwr&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;STM&lt;/span&gt;32&lt;span class="n"&gt;F&lt;/span&gt;4&lt;span class="n"&gt;xx_HAL_Driver&lt;/span&gt;/&lt;span class="n"&gt;Inc&lt;/span&gt;/&lt;span class="n"&gt;stm&lt;/span&gt;32&lt;span class="n"&gt;f&lt;/span&gt;4&lt;span class="n"&gt;xx_hal_pwr_ex&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Drivers&lt;/span&gt;/&lt;span class="n"&gt;STM&lt;/span&gt;32&lt;span class="n"&gt;F&lt;/span&gt;4&lt;span class="n"&gt;xx_HAL_Driver&lt;/span&gt;/&lt;span class="n"&gt;Inc&lt;/span&gt;/&lt;span class="n"&gt;stm&lt;/span&gt;32&lt;span class="n"&gt;f&lt;/span&gt;4&lt;span class="n"&gt;xx_hal_uart&lt;/span&gt;.&lt;span class="n"&gt;h&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Core/Inc/gpio.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Core/Inc/main.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Core/Inc/stm32f4xx_hal_conf.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_rcc.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_def.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/CMSIS/Device/ST/STM32F4xx/Include/stm32f411xe.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/CMSIS/Include/core_cm4.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/CMSIS/Include/cmsis_version.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/CMSIS/Include/cmsis_compiler.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/CMSIS/Include/cmsis_gcc.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/CMSIS/Include/mpu_armv7.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/CMSIS/Device/ST/STM32F4xx/Include/system_stm32f4xx.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/STM32F4xx_HAL_Driver/Inc/Legacy/stm32_hal_legacy.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_rcc_ex.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_gpio.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_gpio_ex.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_exti.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_dma.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_dma_ex.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_cortex.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_flash.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_flash_ex.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_flash_ramfunc.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_pwr.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_pwr_ex.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_uart.h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个是gpio.d，看着是不是很熟悉，感觉和前面那个《&lt;a class="link" href="https://blog.csdn.net/qwe5959798/article/details/112367495" target="_blank" rel="noopener"&#10; &gt;(GCC)STM32CubeMX生成的Makefile详解&lt;/a&gt;》说的把生成指令展开后C_INCLUDES、C_SOURCES生成的那一套很像？像就对了，这东西就是为了生成.d文件最顶部那个目标文件而存在的，而这里的gpio.d文件中所指的其实就是gpio.o，其余同理。&lt;/p&gt;&#10;&lt;h2 id="结语"&gt;&lt;a href="#%e7%bb%93%e8%af%ad" class="header-anchor"&gt;&lt;/a&gt;结语&#10;&lt;/h2&gt;&lt;p&gt;好了，看到这你应该基本上理解了这个Makefile内部的功能和作用了，配合我找的这些资料以及官方文档，相信你可以学到更多。&lt;/p&gt;&#10;&lt;p&gt;本文的存在更多是类似一个学习笔记，而且本人本身才疏学浅，里面内容不免可能会存在一些矛盾错误或疏漏的地方，如果发现欢迎指出。&lt;/p&gt;&#10;</description></item><item><title>深度底层剖析，你所不知道的printf</title><link>https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/%E6%B7%B1%E5%BA%A6%E5%BA%95%E5%B1%82%E5%89%96%E6%9E%90%E4%BD%A0%E6%89%80%E4%B8%8D%E7%9F%A5%E9%81%93%E7%9A%84printf/</link><pubDate>Thu, 19 Aug 2021 21:02:23 +0800</pubDate><guid>https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/%E6%B7%B1%E5%BA%A6%E5%BA%95%E5%B1%82%E5%89%96%E6%9E%90%E4%BD%A0%E6%89%80%E4%B8%8D%E7%9F%A5%E9%81%93%E7%9A%84printf/</guid><description>&lt;img src="https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/%E6%B7%B1%E5%BA%A6%E5%BA%95%E5%B1%82%E5%89%96%E6%9E%90%E4%BD%A0%E6%89%80%E4%B8%8D%E7%9F%A5%E9%81%93%E7%9A%84printf/cover.jpg" alt="Featured image of post 深度底层剖析，你所不知道的printf" /&gt;&lt;!-- @import "[TOC]" {cmd="toc" depthFrom=1 depthTo=6 orderedList=false} --&gt;&#10;&lt;!-- code_chunk_output --&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e6%b3%a8%e6%84%8f" &gt;注意&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e8%a7%86%e9%a2%91" &gt;视频&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e5%86%8d%e8%a7%82printf%e5%87%bd%e6%95%b0" &gt;再观printf函数&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#print%e4%b8%ba%e4%bb%80%e4%b9%88%e8%a6%81%e5%8a%a0%e4%b8%aaf" &gt;print为什么要加个f&lt;/a&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e6%a0%bc%e5%bc%8f%e7%ac%a6%e6%98%af%e4%bb%80%e4%b9%88%e6%97%b6%e5%80%99%e8%a2%ab%e8%a7%a3%e6%9e%90%e7%9a%84" &gt;格式符是什么时候被解析的？&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e5%a6%82%e4%bd%95%e5%ae%9e%e7%8e%b0%e5%8f%98%e5%8f%82%e5%87%bd%e6%95%b0" &gt;如何实现变参函数&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e6%9d%a5%e5%ae%9e%e7%8e%b0%e4%b8%80%e4%b8%aaprintf%e5%90%a7" &gt;来实现一个printf吧&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#printf%e6%98%af%e5%90%a6%e6%9c%89%e6%a3%80%e6%b5%8b%e5%8a%9f%e8%83%bd" &gt;printf是否有检测功能&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#printf%e5%8f%aa%e8%83%bd%e8%be%93%e5%87%ba%e5%9c%a8%e5%91%bd%e4%bb%a4%e8%a1%8c%e5%90%97" &gt;printf只能输出在命令行吗&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e7%bb%93%e8%af%ad" &gt;结语&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;!-- /code_chunk_output --&gt;&#10;&lt;h2 id="注意"&gt;&lt;a href="#%e6%b3%a8%e6%84%8f" class="header-anchor"&gt;&lt;/a&gt;注意&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;本文为针对C语言的基础技术向，更适合刚入门需要进阶的同学技术进阶使用，当然我会尽量用简单的语言让哪怕是初学者也可以看得懂，核心知识有如下部分：&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;变参函数的概念和使用&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;__attribute__(())&lt;/code&gt;的概念和使用&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;printf函数的实现&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="视频"&gt;&lt;a href="#%e8%a7%86%e9%a2%91" class="header-anchor"&gt;&lt;/a&gt;视频&#10;&lt;/h2&gt;&lt;p&gt;本文可以结合视频一起食用，效果更佳：&lt;a class="link" href="https://www.bilibili.com/video/BV1p64y1e7YM" target="_blank" rel="noopener"&#10; &gt;视频链接&lt;/a&gt;&lt;/p&gt;&#10;&lt;h2 id="再观printf函数"&gt;&lt;a href="#%e5%86%8d%e8%a7%82printf%e5%87%bd%e6%95%b0" class="header-anchor"&gt;&lt;/a&gt;再观printf函数&#10;&lt;/h2&gt;&lt;p&gt;相信绝大部分同学写的第一个程序，应该就是大名鼎鼎的&lt;code&gt;Hello World&lt;/code&gt;程序了，这个程序闻名于著名的《C语言程序设计(The C Programming Language)》（C语言之父丹尼斯·里奇（Dennis Ritchie）著）一书中，非常经典，以至于程序员们学习任何语言，都会先用这个语言运行个Hello World出来。&lt;/p&gt;&#10;&lt;p&gt;在C语言中，这个程序一般写出来是这个样子的：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello World!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果在命令行运行这个程序的话，你将获得一行&lt;code&gt;Hello World!&lt;/code&gt;输出。&lt;/p&gt;&#10;&lt;p&gt;如果你是一个不喜欢思考的初学者，可能会认为printf也许是C语言里面最基础最简单的函数了，毕竟这个程序这么简洁、格式这么规范、使用这么简单、甚至闭着眼睛都不会写错。&lt;/p&gt;&#10;&lt;p&gt;但如果我们往细究往深了想呢？printf它是如何实现的呢？我们是否可以实现一个自己的printf函数呢？为什么它会运行在命令行中而不是从屏幕某个规定的位置显示呢……&lt;/p&gt;&#10;&lt;p&gt;这时你可能会发现，woc，printf似乎比我们想象的要复杂太多了，你以为的简单小函数，其实却是个超级大boss。不过不要担心，我们会从基础开始讲，而且我会保证尽量说得简单明了。&lt;/p&gt;&#10;&lt;h2 id="print为什么要加个f"&gt;&lt;a href="#print%e4%b8%ba%e4%bb%80%e4%b9%88%e8%a6%81%e5%8a%a0%e4%b8%aaf" class="header-anchor"&gt;&lt;/a&gt;print为什么要加个f&#10;&lt;/h2&gt;&lt;p&gt;现在，我们重新抱着认真学习的态度来观察printf这个函数吧。首先我们从名字来解析一下。&lt;/p&gt;&#10;&lt;p&gt;我们知道，在英语中，print有打印、印刷的意思，这个词语完全可以解释将字符串打印到电脑屏幕上这个过程，那么为什么这个函数的名字要加上f呢？&lt;/p&gt;&#10;&lt;p&gt;其实这个f是format的缩写，即格式化的意思，printf其实为格式化打印的意思。那么格式化这个是怎么来的？&lt;/p&gt;&#10;&lt;p&gt;现在想想，如果我们希望在屏幕上输出一个变量该怎么做呢？最简单的方法就是使用格式字符，就如下面这个程序一样：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;a = %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个函数将会在屏幕上输出一行&lt;code&gt;a = 25&lt;/code&gt;，在这个过程中%d就是变量a的格式符，它在字符串中占位，然后字符串在输出的时候，遇到了这个占位符，就会解析a的具体值，并把它转换为字符串的形式输出出来。&lt;/p&gt;&#10;&lt;p&gt;现在从这个功能中我们其实可以发现很多问题，我们来逐一解释：&lt;/p&gt;&#10;&lt;h3 id="格式符是什么时候被解析的"&gt;&lt;a href="#%e6%a0%bc%e5%bc%8f%e7%ac%a6%e6%98%af%e4%bb%80%e4%b9%88%e6%97%b6%e5%80%99%e8%a2%ab%e8%a7%a3%e6%9e%90%e7%9a%84" class="header-anchor"&gt;&lt;/a&gt;格式符是什么时候被解析的？&#10;&lt;/h3&gt;&lt;p&gt;这个问题是我在学习理解printf的时候第一个思考的问题，即格式符是如何什么时候被解析的，答案有两种，对应了两种不同的结果。&lt;/p&gt;&#10;&lt;p&gt;首先是在编译阶段被解析，这种方式的话也有两种情况，一是编译器有针对printf这类函数的优化，二是编译器会主动把字符串中的格式符变成某种执行效果。而另一种方案是printf函数内部实现的解析格式符。&lt;/p&gt;&#10;&lt;p&gt;我们可以用如下的程序来测试（为了方便，后面我们生成程序的名称都为demo.exe）：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;a=%d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;putchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后我们把它们编译完成后，在命令行中使用&lt;code&gt;./demo.exe b=%d&lt;/code&gt;来运行（如果使用的某种IDE，可以打开工程文件夹，找到输出exe文件，然后在文件夹中按住&lt;code&gt;shift+右键&lt;/code&gt;，打开powershell，然后用&lt;code&gt;./文件名.exe b=%d&lt;/code&gt;的方式运行即可）。&lt;/p&gt;&#10;&lt;p&gt;最后我们会得到两行输出&lt;code&gt;a=1&lt;/code&gt;和&lt;code&gt;b=2&lt;/code&gt;。&lt;/p&gt;&#10;&lt;p&gt;对于上面的程序，我们来理解一下：&lt;/p&gt;&#10;&lt;p&gt;其中首先是main函数的部分，可以发现我们在里面写了两个参数，其实这种写法才是C语言main函数的标准写法，具体可以参考我之前写的《&lt;a class="link" href="https://blog.csdn.net/qq_44884716/article/details/111412695?spm=1001.2014.3001.5501" target="_blank" rel="noopener"&#10; &gt;C的main函数解析&lt;/a&gt;》这篇博客，这里不作详述，这里只说一下其中第八行的&lt;code&gt;argv[1]&lt;/code&gt;其实就代表了我们开启程序时输入的第一个参数字符串，在我们的示例里面也就是&lt;code&gt;b=%d&lt;/code&gt;一句。那么我们从第一个输出a=1可以看出，这里的输出语句并不是直接写在printf函数里的，但是占位符仍然有效，而第二个b=2则表明了我们通过外部未知的字符串中的占位符也实现了占位符效果。故可知占位符实际上是在printf中被解析的。&lt;/p&gt;&#10;&lt;p&gt;既然知道了这个，那么printf解析的方案其实也就很容易出来了，程序通过检测百分号&lt;code&gt;%&lt;/code&gt;寻找占位符，并根据不同的占位符将数字转换成字符串。&lt;/p&gt;&#10;&lt;h3 id="如何实现变参函数"&gt;&lt;a href="#%e5%a6%82%e4%bd%95%e5%ae%9e%e7%8e%b0%e5%8f%98%e5%8f%82%e5%87%bd%e6%95%b0" class="header-anchor"&gt;&lt;/a&gt;如何实现变参函数&#10;&lt;/h3&gt;&lt;p&gt;既然知道了如何解析格式符，那么我们似乎就可以实现printf函数了？可是等一下，我们在写printf的时候为什么可以写多个参数？&lt;/p&gt;&#10;&lt;p&gt;一般而言，如果我们仅仅跟着学校学习的那点C语言知识，肯定不会讲什么变参函数的，但是printf这个函数的存在却离不开变参函数这个概念。而且，配合变参函数，你还可以实现一些类似于其它更加高级语言的重载、默认参数等功能。&lt;/p&gt;&#10;&lt;p&gt;如果需要实现变参函数，那么有一个库文件就很关键了，那就是&lt;code&gt;stdarg.h&lt;/code&gt;。你首先需要包含这个库，然后按照规定的写法就可以实现变参函数了。例如下面我就写了个简单的变参整数加法函数：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdarg.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;MySum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;va_list&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#9;&lt;span class="c1"&gt;// 一个宏定义类型，通过它我们可以访问参数数据&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;va_start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#9;&lt;span class="c1"&gt;// 确定起始参数&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nf"&gt;va_arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#9;&lt;span class="c1"&gt;// 从起始参数开始取一个int类型的数据并加到sum中，同时num将会指向下一个参数&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;va_end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#9;&lt;span class="c1"&gt;// 释放&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过这个函数我们即可以实现一个变参的加法。我们来看一下这里的写法，其实很简单，除了格式要求在函数的形参列表末尾加上三个点表示这是个变参函数外，重点也就一个数据类型和三个函数。&lt;/p&gt;&#10;&lt;p&gt;不过为了防止看不懂，我们来从原理上理解一下这个功能。（此部分仅作参考，我并没有实际去看编译器的内容，而源文件也被隐藏起来了，故下面的内容大多是基于我自己的分析）。&lt;/p&gt;&#10;&lt;p&gt;首先是三个点的作用，很显然这个东西是给编译器看的，因为如果不加三个点，那么我们使用函数的时候，实参与形参个数对不上，编译器就会报错，而这三个点就可以告诉编译器，这是个变参函数，实参多了少了你别叫唤。&lt;/p&gt;&#10;&lt;p&gt;然后是一个数据类型即&lt;code&gt;va_list&lt;/code&gt;，这个类型从某种意义上感觉应该是个空指针，这个指针可以用来在栈中取数据。当然它也可能是个结构体，但至少绝对拥有指针的功能。&lt;/p&gt;&#10;&lt;p&gt;而剩下三个函数中，第一个调用的是&lt;code&gt;va_start&lt;/code&gt;，它应该是用来对&lt;code&gt;va_list&lt;/code&gt;这个指针赋初值。这里我认为应该是程序在编译运行后，函数的实参应该是放在一个栈里的，并且是有规律有顺序的存放的，那么我们要取一个数据，只要确定了这个数据的首地址（&lt;code&gt;va_list指向的位置&lt;/code&gt;）和长度（数据类型），就可以把数据正确取出来了，取出来后因为数据被整齐地排列着，所以指针被完美地跳转到下一个实参的首地址。而&lt;code&gt;va_start&lt;/code&gt;其实作用就是确定这个实参列表整体的首地址。&lt;/p&gt;&#10;&lt;p&gt;然后是第二个函数，在程序中被反复调用的&lt;code&gt;va_arg&lt;/code&gt;函数，显然通过我们刚才的分析，应该不难知道这个函数其实就是用来取数据同时移动指针的，在这个函数的参数中，除了要取数据的&lt;code&gt;va_list&lt;/code&gt;，还包括了要取的数据类型（虽然不知道为什么这个数据类型可以直接被写成类型的名称形式，应该是宏定义的一种用法），然后通过这个函数，我们就可以按照格式取出数据，同时把&lt;code&gt;va_list&lt;/code&gt;跳转到下一个参数的位置。&lt;/p&gt;&#10;&lt;p&gt;最后第三个函数，我们可以调用&lt;code&gt;va_end&lt;/code&gt;把指针指向一个空地址，防止野指针对内存造成破坏。&lt;/p&gt;&#10;&lt;p&gt;除此之外，其实stdarg中还有很多其它的函数，不过我们平常不大用得到，如果感兴趣的话可以自行研究研究。&lt;/p&gt;&#10;&lt;p&gt;现在，我们来试试刚刚写的程序吧，在主函数中如此调用：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;MySum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;%d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后我们可以得到一个&lt;code&gt;15&lt;/code&gt;的输出。&lt;/p&gt;&#10;&lt;h3 id="来实现一个printf吧"&gt;&lt;a href="#%e6%9d%a5%e5%ae%9e%e7%8e%b0%e4%b8%80%e4%b8%aaprintf%e5%90%a7" class="header-anchor"&gt;&lt;/a&gt;来实现一个printf吧&#10;&lt;/h3&gt;&lt;p&gt;现在我们来实现一个printf吧，为了方便我用比较简单潦草的程序只写了一个&lt;code&gt;%d&lt;/code&gt;的识别，而且用了一些goto语句，不过总体来说还是可以看懂的。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;MyPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="p"&gt;...)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;va_list&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;va_start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;intStr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="sc"&gt;&amp;#39;%&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="sc"&gt;&amp;#39;d&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;itoa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;va_arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;intStr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intStr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intStr&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sc"&gt;&amp;#39;\0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;putchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intStr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;putchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;%&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;putchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="sc"&gt;&amp;#39;\0&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;goto&lt;/span&gt; &lt;span class="n"&gt;OUT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;putchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nl"&gt;OUT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面这个程序其实你们自己都可以写，如果还是有点不懂的话可以仔细读一下，里面用的函数都是非常基础的API，现在我们测试一下：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;MyPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;%d %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;%c %x&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个程序可以用来测试MyPrint的以下功能：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;正常输出打印字符串&lt;/li&gt;&#10;&lt;li&gt;格式字符%d是否有用&lt;/li&gt;&#10;&lt;li&gt;%c和%x应该没用&lt;/li&gt;&#10;&lt;li&gt;%c和%x的存在不会影响编译警告，同时也不会读取更多或更少的参数&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;现在，只要我们继续填充内容，就可以实现自己的printf功能了，甚至可以添加一些自己的格式符，来实现一些更加复杂高级的输出。&lt;/p&gt;&#10;&lt;h2 id="printf是否有检测功能"&gt;&lt;a href="#printf%e6%98%af%e5%90%a6%e6%9c%89%e6%a3%80%e6%b5%8b%e5%8a%9f%e8%83%bd" class="header-anchor"&gt;&lt;/a&gt;printf是否有检测功能&#10;&lt;/h2&gt;&lt;p&gt;我们经过刚才的研究发现，在使用printf的时候哪怕格式字符和数据的个数对不上号，我的编译器似乎也不会报错（这里仅指代MinGW，如果你使用的codeblocks或者其它开源IDE，可能结果与我一样），但是有的编译器不一样，例如针对嵌入式的&lt;code&gt;gcc-arm-none-eabi&lt;/code&gt;编译器，或者一些其它的IDE自研编译器，它们有可能会报错或警告，为什么呢？printf是否拥有某种检测功能，来防止我们错误地多填或者少写实参呢？事实上是有的，不过有的编译器没有用或者没有实现，这种功能一般专属于GNU版本的编译器，那就是使用&lt;code&gt;__attribute(())_&lt;/code&gt;功能。&lt;/p&gt;&#10;&lt;p&gt;我们知道，平常我们编程的时候，编译器说什么，我们就得听什么，必须完全听从编译器的指挥。从绝大部分情况来看，它很方便也很可靠，毕竟不用动脑子按规范来就行。但是C语言是一个非常贴近硬件的语言，我们很多时候可能会完成一些匪夷所思的操作来实现某种功能，还有时候我们有些操作非常危险需要用一种方法来时刻提醒我们的大脑，那么我们就可以使用&lt;code&gt;__attribute__&lt;/code&gt;了，这个关键字可以被编译器识别，然后根据其参数，编译器将会执行相应的操作。从另一种方面来讲，&lt;code&gt;__attribute__&lt;/code&gt;是专门针对编译器的指令，我们可以用它实现一些很方便的功能，最经典的就是&lt;code&gt;__attribute__((weak))&lt;/code&gt;了，这个功能可以让函数被弱化，如果在同一个程序中遇到了两个同名同参同返回的函数，那么编译器就会去编译没被弱化或者说更强的那一个函数，这样我们就可以实现函数的重写覆盖功能。&lt;/p&gt;&#10;&lt;p&gt;当然，&lt;code&gt;__attribute__&lt;/code&gt;的用法其实有很多，我们再举一个常用的例子，也就是&lt;code&gt;__attribute__((pack))&lt;/code&gt;这个功能，它可以把结构体尽量地压缩到最小体积（平常为了保证速度，结构体会按照速度最优的方案来存储）。&lt;/p&gt;&#10;&lt;p&gt;而这里，我们同样可以使用&lt;code&gt;__attribute__((format(printf, 1, 2)))&lt;/code&gt;，来实现对printf的格式检测，这样如果我们的格式符和实参个数不对应，就可以被检测到了。（不过MinGW好像没法实现这个功能，如果有使用&lt;code&gt;gcc-arm-none-eabi&lt;/code&gt;的同学可以试试）&lt;/p&gt;&#10;&lt;h2 id="printf只能输出在命令行吗"&gt;&lt;a href="#printf%e5%8f%aa%e8%83%bd%e8%be%93%e5%87%ba%e5%9c%a8%e5%91%bd%e4%bb%a4%e8%a1%8c%e5%90%97" class="header-anchor"&gt;&lt;/a&gt;printf只能输出在命令行吗&#10;&lt;/h2&gt;&lt;p&gt;目前我在Windows上使用MinGW测试，暂时没有发现其printf有重定向功能，不过这个应该是为了安全考虑，毕竟你在Windows上实现在其它地方打印，一般需要使用Windows提供的API，否则很容易出问题，而如Linux这些系统，大多也是如此。&lt;/p&gt;&#10;&lt;p&gt;不过对于嵌入式来说，重写pritnf就是很平常很普通的任务了，我们一般会把printf重写在串口上，但是在写了屏幕驱动后，也可以把printf重新封装到屏幕上，而Windows运行的printf应该就是把printf连接在了Windows的屏幕驱动中，然后通过调用驱动的方式来实现的数据打印功能。&lt;/p&gt;&#10;&lt;p&gt;本质上printf其实可以当作连续按照格式使用putchar的函数，而putchar也就打印字符的函数，那么我们只要可以确定每个putchar打印的位置，那么printf的使用就迎刃而解了。&lt;/p&gt;&#10;&lt;h2 id="结语"&gt;&lt;a href="#%e7%bb%93%e8%af%ad" class="header-anchor"&gt;&lt;/a&gt;结语&#10;&lt;/h2&gt;&lt;p&gt;现在你已经基本懂得了printf是如何实现的了，那么用这个方法反推，其实你应该也可以实现scanf的功能，因为它们的思想都是大致相同的。从觉得printf是一个非常简单的函数，到觉得printf好像非常麻烦，再到我们现在将它几乎完整地剖析了一遍，现在回头看，它的实现机理其实并不算简单，但也没那么复杂，重点是要主动去思考，去想，去理解，去实验。&lt;/p&gt;&#10;</description></item><item><title>C宏定义连接符#和##及其应用</title><link>https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/c%E5%AE%8F%E5%AE%9A%E4%B9%89%E8%BF%9E%E6%8E%A5%E7%AC%A6%E5%8F%8A%E5%85%B6%E5%BA%94%E7%94%A8/</link><pubDate>Wed, 16 Jun 2021 18:22:21 +0800</pubDate><guid>https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/c%E5%AE%8F%E5%AE%9A%E4%B9%89%E8%BF%9E%E6%8E%A5%E7%AC%A6%E5%8F%8A%E5%85%B6%E5%BA%94%E7%94%A8/</guid><description>&lt;img src="https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/c%E5%AE%8F%E5%AE%9A%E4%B9%89%E8%BF%9E%E6%8E%A5%E7%AC%A6%E5%8F%8A%E5%85%B6%E5%BA%94%E7%94%A8/cover.jpg" alt="Featured image of post C宏定义连接符#和##及其应用" /&gt;&lt;p&gt;在学习LwIP的时候，发现源码中出现了&lt;code&gt;#define LWIP_MEMPOOL(name, num, size, desc) MEMP_##name&lt;/code&gt;这样的语句，了解到了C编译器中##这个连接符。顺便查了一下资料，还发现了#这个字符转换符。&lt;/p&gt;&#10;&lt;h2 id="功能"&gt;&lt;a href="#%e5%8a%9f%e8%83%bd" class="header-anchor"&gt;&lt;/a&gt;功能&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;##&lt;/code&gt;可以作为宏定义中的变量替换，&lt;code&gt;#&lt;/code&gt;则作为字符替换，一般他们都是用于带参宏定义中。&lt;/p&gt;&#10;&lt;p&gt;比如：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define func1(a) printf(#a&amp;#34;\n&amp;#34;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define func(num, a) func##num(a)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;func1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上述程序将会输出两个hello。&lt;/p&gt;&#10;&lt;p&gt;第一个hello源自于&lt;code&gt;func1(hello);&lt;/code&gt;这句话因为宏定义将会变成&lt;code&gt;printf(“hello”);&lt;/code&gt;其中hello之所以变成字符串，就是因为在宏定义的时候使用了&lt;code&gt;#&lt;/code&gt;，另外相邻且未被任何字符隔开的两个字符串在C中会被合并在一起，故这里相当于还加上了一个回车。&lt;/p&gt;&#10;&lt;p&gt;第二个hello源自于&lt;code&gt;func(1, hello);&lt;/code&gt;这句话因为宏定义首先会变成&lt;code&gt;func1(hello);&lt;/code&gt;其中之所以参数1会出现在变量名中，就是因为在宏定义中使用了&lt;code&gt;##&lt;/code&gt;，它相当于将宏定义中的参数num变成了真正Token中的内容。Token可以理解为我们在C语言中写的变量名、函数名等等。然后&lt;code&gt;func1(hello);&lt;/code&gt;又变成&lt;code&gt;printf(&amp;quot;hello&amp;quot;);&lt;/code&gt;。&lt;/p&gt;&#10;&lt;h2 id="应用"&gt;&lt;a href="#%e5%ba%94%e7%94%a8" class="header-anchor"&gt;&lt;/a&gt;应用&#10;&lt;/h2&gt;&lt;p&gt;它们的应用不在于提高代码效率或缩减体积，而在于简化编程难度和提高易读性。&lt;/p&gt;&#10;&lt;p&gt;比如，我有一堆字符串口令，为了方便，我对它们进行了宏定义：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define TEST_HELLO &#9;&amp;#34;Hello&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define TEST_BYE&#9;&amp;#34;Bye&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define TEST_NAME1&#9;&amp;#34;Tom&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define TEST_NAME2&#9;&amp;#34;Jerry&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;现在，我希望把这几个口令以一定的方式打印出来，最直接的方法就是如下：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;%s %s %s %s&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TEST_HELLO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TEST_NAME1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TEST_BYE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TEST_NAME2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;不过上述的方式太单一了，而且封装程度不好，如果我们未来想到一个新的问候词要替换呢？可能有人想到用这样的方法来替换：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SaySomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;sth1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;sth2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;name1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;name2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;%s %s %s %s&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sth1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sth2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样封装后我们使用：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;SaySomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TEST_HELLO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TEST_NAME1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TEST_BYE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TEST_NAME2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;就可以完成上面的工作了，但是似乎还是太麻烦而且可扩展性以及封装度有点差，这时我们可以观察上面的所有问候语都是以&lt;code&gt;TEST_&lt;/code&gt;开头的且后面的问候句与下划线后的文字直接相关，而人的名字则以&lt;code&gt;TEST_NAME&lt;/code&gt;开头，然后接上一个数字编号，那么我们是否可以依靠这个来做点什么呢？&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define SaySomething(sth1, sth2, name1, name2) printf(#sth1&amp;#34; %s &amp;#34;#sth2&amp;#34; %s&amp;#34;, TEST_NAME##name1, TEST_NAME##name2)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过这样一个封装，我们就可以实现前面的功能了，用法如下：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;SaySomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Bye&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;之所以它们可以连接在一起是因为C语言中直接相连的两个字符串是会被视为一个整体的。&lt;/p&gt;&#10;&lt;p&gt;由此可见当我们宏定义了一大堆功能类似名字类似且可以相互替换的常量时，&lt;code&gt;#&lt;/code&gt;和&lt;code&gt;##&lt;/code&gt;就变得非常有用了。&lt;/p&gt;&#10;&lt;h2 id="效果图"&gt;&lt;a href="#%e6%95%88%e6%9e%9c%e5%9b%be" class="header-anchor"&gt;&lt;/a&gt;效果图&#10;&lt;/h2&gt;&lt;img alt="在这里插入图片描述" class="gallery-image" data-flex-basis="796px" data-flex-grow="331" height="291" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/c%E5%AE%8F%E5%AE%9A%E4%B9%89%E8%BF%9E%E6%8E%A5%E7%AC%A6%E5%8F%8A%E5%85%B6%E5%BA%94%E7%94%A8/img/2f064b62237548df93038e322b1de940.webp" width="966"&gt;&lt;img alt="在这里插入图片描述" class="gallery-image" data-flex-basis="1072px" data-flex-grow="446" height="64" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/c%E5%AE%8F%E5%AE%9A%E4%B9%89%E8%BF%9E%E6%8E%A5%E7%AC%A6%E5%8F%8A%E5%85%B6%E5%BA%94%E7%94%A8/img/5cf23f0dcea0655e79b1b36e365ff762.webp" width="286"&gt;</description></item><item><title>C语言可以使用变量定义数组</title><link>https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/c%E8%AF%AD%E8%A8%80%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E5%8F%98%E9%87%8F%E5%AE%9A%E4%B9%89%E6%95%B0%E7%BB%84/</link><pubDate>Mon, 19 Apr 2021 17:05:43 +0800</pubDate><guid>https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/c%E8%AF%AD%E8%A8%80%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E5%8F%98%E9%87%8F%E5%AE%9A%E4%B9%89%E6%95%B0%E7%BB%84/</guid><description>&lt;img src="https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/c%E8%AF%AD%E8%A8%80%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E5%8F%98%E9%87%8F%E5%AE%9A%E4%B9%89%E6%95%B0%E7%BB%84/cover.jpg" alt="Featured image of post C语言可以使用变量定义数组" /&gt;&lt;p&gt;这是在一次研讨会中发现的我知识上的纰漏，在此进行记录。&lt;/p&gt;&#10;&lt;p&gt;当时想给学弟学妹讲一下关于动态内存的问题，在讲述时我用了一个初始化变量时不能用变量作为下标。例如：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然而事实上，在这样写了之后我发现编译没有出错，这和我最开始学C语言时老师给我们讲的内容并不相同。我最初怀疑时因为此时i已经被赋值了而后在此期间没有进行计算，所以编译器可能将其直接作为一个宏定义来解析了。但是我们又尝试了如下两种写法。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;scanf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;%d&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;此时编译器仍然没有报错，而且生成的程序运行起来也是正常的。故而这样的写法其实是正确的，其运行逻辑应该是这种语句在被编译的时候成为了类似于malloc的语句，同时在后面的某个位置自动添加了free，不过因为我对汇编并不是特别熟，只能从理论层面大概分析一下，具体内容各位可以使用反汇编自行查看。&lt;/p&gt;&#10;&lt;p&gt;不过需要注意的是，在定义的时候不能直接赋值：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;原因可能在于等号赋值是先右后左，虽然在普通直接使用常量定义数组的时候没有关系，但那应该是在编译状态就可以计算出的内容，只要赋值的长度不超就没事，而这种变量赋值则类似于一种动态分配，编译器并不能预测在运行时这个变量究竟是多少，哪怕你知道它只能是这么多，但是编译器并没有那么智能，不如就直接报错处理了。&lt;/p&gt;&#10;&lt;p&gt;考虑到最开始学到这个知识的时候老师讲课用的书是谭浩强的那本，限于时代因素那本书使用的C语言标准应该是在C89左右，而当时实验课我们使用DEV-C++进行编译也会遇到这种问题，故而我怀疑可能在C99或者C11的版本中发生了某种改变，毕竟我现在用的是C11的gcc了。不过具体是什么时候不重要，记住这个结论就好了。&lt;/p&gt;&#10;&lt;p&gt;另外我真认为各高校确实该换本教科书了……&lt;/p&gt;&#10;</description></item><item><title>C/C++中malloc的强制转换</title><link>https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/malloc%E7%9A%84%E5%BC%BA%E5%88%B6%E8%BD%AC%E6%8D%A2/</link><pubDate>Sat, 26 Dec 2020 18:14:00 +0800</pubDate><guid>https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/malloc%E7%9A%84%E5%BC%BA%E5%88%B6%E8%BD%AC%E6%8D%A2/</guid><description>&lt;img src="https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/malloc%E7%9A%84%E5%BC%BA%E5%88%B6%E8%BD%AC%E6%8D%A2/cover.jpg" alt="Featured image of post C/C++中malloc的强制转换" /&gt;&lt;p&gt;&lt;em&gt;因为数据结构课在使用malloc函数的时候一直很迷惑，为什么一定需要在前面加上一个强制转换语句，像是这样：&lt;code&gt;int *a = (int *)malloc(sizeof(int)*3);&lt;/code&gt;&lt;/em&gt;。&lt;/p&gt;&#10;&lt;p&gt;为此我在菜鸟教程的malloc()函数介绍中找到了关于malloc的声明：&lt;code&gt;void *malloc(size_t size)&lt;/code&gt;，显然加上一个强制转换语句并不是标准语法必须的东西，但是在菜鸟教程下面的举例中是按照强制转换的写法来写的，可惜没有说为什么。为此我尝试了不加强制转换语句的malloc来直接分配空间，在gcc编译后并没有报错或者发出警告。&lt;/p&gt;&#10;&lt;p&gt;这就很神奇了，我换了多个姿势来对这两种用法进行测试，包括但不限于不同大小&lt;code&gt;long *a = malloc(sizeof(int)*2)&lt;/code&gt;或者数组结构&lt;code&gt;int *b = malloc(size(int)*3)&lt;/code&gt;，他们都没有报错或警告，而强制转换亦是如此。&lt;/p&gt;&#10;&lt;p&gt;就在我怀疑是某种错误的如同void main这种异类写法产生了曼德拉效应时，我看到了&lt;a class="link" href="https://www.cnblogs.com/esta-pessoa/archive/2013/04/29/3051119.html" target="_blank" rel="noopener"&#10; &gt;另一篇博客&lt;/a&gt;的记录：在ANSI/ISO标准C下，我们是可以不使用强制转换来直接使用malloc的，并且使用强制转换还可能掩盖malloc()声明错误时产生的重要警告，反而不如直接使用malloc。但是使用malloc强制转换的好处在于，可以更方便地移植到C++中，因为C++似乎并不支持这种隐式转换。&lt;/p&gt;&#10;&lt;p&gt;根据这个帖子我大概猜测了一下国内这种喜欢在malloc函数前加强制转换命令的原因，除了个别学校在教学生C语言的时候把C/C++混为一谈，导致学生用C++的语法来理解C语言（这种情况真的不少），还有很大原因是因为国内高校很喜欢用Dev-C++这类常年未更新用着远古标准的IDE。&lt;/p&gt;&#10;</description></item><item><title>C的main函数解析</title><link>https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/c%E7%9A%84main%E5%87%BD%E6%95%B0%E8%A7%A3%E6%9E%90/</link><pubDate>Sun, 20 Dec 2020 00:14:50 +0800</pubDate><guid>https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/c%E7%9A%84main%E5%87%BD%E6%95%B0%E8%A7%A3%E6%9E%90/</guid><description>&lt;img src="https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/c%E7%9A%84main%E5%87%BD%E6%95%B0%E8%A7%A3%E6%9E%90/cover.jpg" alt="Featured image of post C的main函数解析" /&gt;&lt;p&gt;&lt;em&gt;终于开始学习Linux的C语言编程了&lt;del&gt;嘤嘤嘤，有种终于入门的感动&lt;/del&gt;&lt;/em&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;em&gt;关于Linux中C语言编程包括vim、gcc、makefile这些工具的用法这些不是本次的主题，我在这里就不详细展开了，本文只阐述一下main函数的参数调用问题。&lt;/em&gt;&lt;/p&gt;&#10;&lt;!-- @import "[TOC]" {cmd="toc" depthFrom=1 depthTo=6 orderedList=false} --&gt;&#10;&lt;!-- code_chunk_output --&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e5%b7%a5%e5%85%b7" &gt;工具&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e5%9f%ba%e6%9c%ac%e5%8e%9f%e7%90%86" &gt;基本原理&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="#%e5%ae%9e%e7%8e%b0%e4%b8%8e%e8%a7%a3%e6%9e%90" &gt;实现与解析&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;!-- /code_chunk_output --&gt;&#10;&lt;h2 id="工具"&gt;&lt;a href="#%e5%b7%a5%e5%85%b7" class="header-anchor"&gt;&lt;/a&gt;工具&#10;&lt;/h2&gt;&lt;p&gt;VirtualBox 6.1.12，Ubuntu 20.04，Code::Blocks，C&lt;/p&gt;&#10;&lt;h2 id="基本原理"&gt;&lt;a href="#%e5%9f%ba%e6%9c%ac%e5%8e%9f%e7%90%86" class="header-anchor"&gt;&lt;/a&gt;基本原理&#10;&lt;/h2&gt;&lt;p&gt;众所周知，main函数对于系统来说其实也只是一个普通的函数，它作为一个接口与系统进行连接，每次系统调用main函数生成的程序文件。而Linux系统其实又是通过C语言写出来的，本质上其实也只是一个C程序。而调用C生成的程序文件其实就等同于将Linux的一个程序运行指针调用这个程序的地址，然后这个程序就执行起来了，而我们可以通过main函数的两个参数接口在调用这个程序的时候进行传参。&lt;/p&gt;&#10;&lt;h2 id="实现与解析"&gt;&lt;a href="#%e5%ae%9e%e7%8e%b0%e4%b8%8e%e8%a7%a3%e6%9e%90" class="header-anchor"&gt;&lt;/a&gt;实现与解析&#10;&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Hello.c，用于测试main参数传递&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;程序地址为：%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;本次传入参数共有%d个&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#9;&lt;span class="c1"&gt;// 通过循环遍历传入所有参数&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&#9;&lt;span class="c1"&gt;// 通过首字母进行快速定位&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="sc"&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="sc"&gt;&amp;#39;W&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;strcmp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;World&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello World!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Is W/w but not World~&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s"&gt;Hello %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;&#9;&lt;span class="c1"&gt;// 是W/w但是并非World&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="sc"&gt;&amp;#39;l&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="sc"&gt;&amp;#39;L&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;strcmp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Linux&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello Linux!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Is W/w but not World~&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s"&gt;Hello %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;&#9;&lt;span class="c1"&gt;// 是L/l但是并非Liunx&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;This is %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里我们可以看到main函数中有两个参数，分别是int类型的argc和char**类型的argv两个参数，当然这两个参数的名字可以变换，就像普通函数的形参一样，但是通常大家都用这两个，相当于约定俗成了。可以看出argv是一个指向char数组的指针数组的数组指针，听上去有点绕，但是用char * argv[]应该就比较好理解了，或者说甚至可以直接当成一个二维数组，其中第一维是一堆地址，每个地址分别指向一个char数组的首地址，而char数组则构成了第二维。而argc则记录了其中第一维的指针argv[]的个数。&lt;/p&gt;&#10;&lt;p&gt;不过值得注意的是，argv有一个默认值argv[0]为程序自身所处地址，比如说如果我们在Windows下检测一个在D:\Code下的test.exe函数，其argv[0]的值就为：D:\Code\test.exe。&lt;/p&gt;&#10;&lt;p&gt;我用如下程序进行了测试：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;当前文件的路径：%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出结果如下：&lt;/p&gt;&#10;&lt;img alt="在这里插入图片描述" class="gallery-image" data-flex-basis="557px" data-flex-grow="232" height="413" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/c%E7%9A%84main%E5%87%BD%E6%95%B0%E8%A7%A3%E6%9E%90/img/c652d7de2b3a300b16e91dc881ec14ee.webp" width="960"&gt;&lt;p&gt;而我们刚才说过argc记录的argv[]的个数，所以同理，我们知道argc的默认值为1。&lt;/p&gt;&#10;&lt;p&gt;所以我们其实就可以把*argv[] 当成一堆指令，每个指令argv[i]在传入到程序中后就是一个char数组的形式。用归类拓展的方式去理解，其实我们平时在cmd中使用的help xx也许其实也相当于是一个程序，help是函数名而xx则是一个参数（当然事实上是不是这样我也不知道，只是做一个例子便于理解，不过想来相差不大）。&lt;/p&gt;&#10;&lt;p&gt;而有了这些认识，我们再看一下上面的程序，就不难理解我的操作了：&lt;/p&gt;&#10;&lt;p&gt;在输出了地址和本次传入参数个数后，程序将会从我传入的第一个参数（也就是argv[1]）开始，一直到最后一个参数，分别将其作为指令进行判断，如果为Linux或World则输出Hello World，其他指令则以This is xx进行输出，而如果判断出首字母为L/l或W/w的指令则会多输出一句Is W/w but not World~\t，最终运行结果如下：&lt;/p&gt;&#10;&lt;img alt="在这里插入图片描述" class="gallery-image" data-flex-basis="713px" data-flex-grow="297" height="179" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/c%E7%9A%84main%E5%87%BD%E6%95%B0%E8%A7%A3%E6%9E%90/img/bb2e858a090083f04784b70b68370c65.webp" width="532"&gt;</description></item><item><title>C和C++在参数调用上的区别</title><link>https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/c%E5%92%8Cc++%E5%9C%A8%E5%8F%82%E6%95%B0%E8%B0%83%E7%94%A8%E4%B8%8A%E7%9A%84%E5%8C%BA%E5%88%AB/</link><pubDate>Sun, 08 Nov 2020 17:10:52 +0800</pubDate><guid>https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/c%E5%92%8Cc++%E5%9C%A8%E5%8F%82%E6%95%B0%E8%B0%83%E7%94%A8%E4%B8%8A%E7%9A%84%E5%8C%BA%E5%88%AB/</guid><description>&lt;img src="https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/c%E5%92%8Cc++%E5%9C%A8%E5%8F%82%E6%95%B0%E8%B0%83%E7%94%A8%E4%B8%8A%E7%9A%84%E5%8C%BA%E5%88%AB/cover.jpg" alt="Featured image of post C和C++在参数调用上的区别" /&gt;&lt;p&gt;&lt;em&gt;在学习 C 语言的数据结构时，我发现教科书上出现的一些代码实际上并不能很好地在 C 语言环境中运行，而需要改成 C++才可以，在网上搜了一下，这里记录 C 和 C++在函数传参上的区别&lt;/em&gt;&lt;/p&gt;&#10;&lt;p&gt;C++的形参有三种写法：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;example_CPP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="cm"&gt;/*a为引用传参*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="cm"&gt;/*b为指针传参*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="cm"&gt;/*c为直接传参*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;三种写法各有用处，这里我们以实例进行研究——&lt;/p&gt;&#10;&lt;p&gt;首先我们打开自己的 IDE，我用的 CodeBlocks，然后输入一下程序：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;example_CPP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/*定义三个变量并输出其值和地址*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;example_CPP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;x的值:&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;x的地址&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;y的值:&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;y的地址&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;z的值:&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;z的地址&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;example_CPP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/*将3个数分别加一*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="cm"&gt;/*a为引用传参，传的是引用值*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;a的值:&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;a的地址&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="cm"&gt;/*b为指针传参，传的是地址*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;b的值:&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;*&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;b的地址&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="cm"&gt;/*c为直接传参，传的是实际值*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;c的值:&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;c的地址&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出结果如下：&#10;&lt;img alt="C++测试结果" class="gallery-image" data-flex-basis="166px" data-flex-grow="69" height="200" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/c%E5%92%8Cc++%E5%9C%A8%E5%8F%82%E6%95%B0%E8%B0%83%E7%94%A8%E4%B8%8A%E7%9A%84%E5%8C%BA%E5%88%AB/img/925a891acf596a733db3fb59b898353d.webp" width="139"&gt;&lt;/p&gt;&#10;&lt;p&gt;当我们使用直接传参时，实际过程可以理解为我们把原来 z 的值赋值给一个新的变量 c，在对 c 进行了一堆操作后释放 c 的空间，而 z 实际上并没有参与到函数中，而仅仅起到一个赋初值的作用。&lt;/p&gt;&#10;&lt;p&gt;而当我们进行指针传递时，可以理解为我们把 y 的地址赋值给一个指针变量 b，而通过指针 b 对其指向的 y 的存储空间进行操作，我们没有直接对 y 进行操作，但是通过指针 b 我们可以间接修改 y 的值。&lt;/p&gt;&#10;&lt;p&gt;至于我方在使用引用传参时，可以理解为直接传参和指针传参的结合版，我们申请了一个新的变量 a，类似于直接传参的变量 c，但是这个变量的地址被赋值为 x 的指针，从效果上来看就有点类似于把 x 临时当成全局变量传递进函数了。这种传参方式非常优秀，相比直接传参可以修改实参真实值，而相比指针传参则不用担心在调用时漏掉了取地址符。&lt;/p&gt;&#10;&lt;p&gt;不过值得注意的是，这种传参方式并不能在 C 语言中使用，至少目前常用的 C99 标准和 C11 标准里我还没看见可以使用的。以下是我在 C 语言里面进行的测试：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;example_CPP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/*定义三个变量并输出其值和地址*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;example_CPP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;example_CPP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="cm"&gt;/*a为引用传参，传的是引用值*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="cm"&gt;/*b为指针传参，传的是地址*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="cm"&gt;/*c为直接传参，传的是实际值*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编译器报错：&lt;/p&gt;&#10;&lt;img alt="C测试编译器报错" class="gallery-image" data-flex-basis="3210px" data-flex-grow="1337" height="61" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.yunwuhai.com/posts/%E5%B5%8C%E5%85%A5%E5%BC%8F/c_cpp/c%E5%92%8Cc++%E5%9C%A8%E5%8F%82%E6%95%B0%E8%B0%83%E7%94%A8%E4%B8%8A%E7%9A%84%E5%8C%BA%E5%88%AB/img/86ace46f0a427868daad34a4ecf4e3fc.webp" width="816"&gt;&lt;p&gt;&lt;em&gt;这两个错误分别报的函数声明和函数定义&lt;/em&gt;&lt;/p&gt;&#10;</description></item></channel></rss>