为什么第二两个printf只输出一个不打印?

在STM32的应用中,我们常常对printf进行重定向的方式来把打印信息printf到我们的串口助手。

在MDK环境中,我们常常使用MicroLIB+fputc的方式实现串口打印功能,即:

要实现fputc函数的原因是:printf函数依赖于fputc函数,重新实现fputc内部从串口发送数据即可间接地实现printf打印输出数据到串口。

不知道大家有没有看过正点原子裸机串口相关的例程,他们的串口例程里不使用MicroLIB,而是使用标准库+fputc的方式。相关代码如:

//标准库需要的支持函数

关于这两种方法的一些说明可以查看Mculover666兄的 《重定向printf函数到串口输出的多种方法》这篇文章。这篇文章中不仅包含上面的两种方法,而且也包含着在GCC中使用标准库重定向printf的方法。

以上的几种方法基本上是改造C库的printf函数来实现串口打印的功能。其实我们也可以自己实现一个串口打印的功能。

printf本身就是一个变参函数,其原型为:

所以,我们要重新封装的一个串口打印函数自然也应该是一个变参函数。具体实现如下:

因为我们使用printf函数基本不使用其返回值,所以这里直接用void类型了。

这里我们使用的是STM32的HAL库,其给我们提供HAL_UART_Transmit接口可以直接把整个发送缓冲区的内容给一次性发出去。

若是基于STM32的标准库,就需要一字节一字节的循环发送出去,具体代码如:

我们也可以使用我们的MyPrintf函数按照上一篇文章: 《C语言、嵌入式中几个非常实用的宏技巧》的方式封装一个宏打印函数:

以上就是我们自定义方式实现的一种串口打印函数。

但是,我想说:对于串口打印的使用,我们没必要自己创建一个打印函数。

看到这,是不是有人想要打我了。。。。看了半天,你却跟我说没必要用。。。

哈哈,别急,我们不应用在串口打印调试方面,那可以用在其它方面呀。

比如最近我在实际应用中:我们的MCU跑的是我们老大自己写的一个小的操作系统+我们公司自己开发的上位机。

我们MCU端与上位机使用的是串口通讯,MCU往上位机发送的数据有两种类型,一种是HEX格式数据,一种是字符串数据。

但是我们下位机的这两种数据,在通过串口发送之前都得统一把数据封包交给那个系统通信任务,然后再由通信任务发出去。

在这里,就不能用printf了。老大也针对他的这个系统实现了一个deb_printf函数用于打印调试。

但是,那个函数既复杂又很鸡肋,稍微复杂一点的数据就打印不出来了。

因此我利用上面的思路给它新封装了一个打印调试函数,很好用,完美地兼容了老大的那个系统。具体代码就不分享了,大体代码、思路如上。

我们在使用串口与ESP8266模块通讯时,可利用类似这样的方式封装一个发送数据的函数,这个函数的使用可以像printf一样简单。

可以以很简单的方式把数据透传至服务端,比如我以前的毕设中就有这么应用:

本书对Linux命令行进行详细的介绍,全书内容包括4个部分,*部分由Shell的介绍开启命令行基础知识的学习之旅;第二部分讲述配置文件的编辑,如何通过命令行控制计算机;第三部分探

版权归出版社和原作者所有,链接已删除,请购买正版

电子版仅供预览,下载后24小时内务必删除,支持正版,喜欢的请购买正版书籍:

本书对Linux命令行进行详细的介绍,全书内容包括4个部分,*部分由Shell的介绍开启命令行基础知识的学习之旅;第二部分讲述配置文件的编辑,如何通过命令行控制计算机;第三部分探讨常见的任务与工具;第四部分全面介绍Shell编程,读者可通过动手编写Shell脚本掌握Linux命令的应用,从而实现常见计算任务的自动化。通过阅读本书,读者将对Linux命令有更加深入的理解,并且可以将其应用到实际的工作中。

重定向到同一个文件中 48 

并将输出结果写入 

第二部分 配置与环境 

第三部分 常见任务与工具 

1、从目录架构角度分析。
windows架构是一个容器,文件夹与文件夹之间存在大小包含关系。
linux架构是一颗树,目录与目录之间存在索引关系。

windows系统以图形界面进行交互。  -> 只需要使用鼠标进行点击
linux系统以命令行方式进行交互。  -> 每一个动作,都是一个命令。

所以说,要操作Linux系统,首先要知道一些linux命令。

二、在linux下使用命令来操作这个系统,那么这些命令是写在哪里的?
命令写在命令行上,而命令行是在一个终端上,所以说首先我们需要打开一个终端。

2、在终端上就会显示一个命令行。
这个命令行其实由一个程序产生的,在我们打开终端后,终端上方默认执行一个bash程序,这个bash程序就会产生一个命令行。

3、这个命令行由什么东西组成?

以"/"根目录开始,一层一层目录地往下写。

例子: 当前我在家目录,我想去根目录下的lib目录,怎么去?

方法二:cd + 相对路径

就是相对于当前的目录而言,这个目标位置在哪里?

   练习1: 假设当前在home目录,想切换到家目录下的Downloads目录,请问用以上两种办法如何切换?

:~$ ls  -> 单独的一个ls就会默认列出当前目录下的文件名。(不包括隐藏文件)

1、main函数使用事项、变量的定义、赋值、数据类型、数据类型在内存中意义,运算符号。
2、ASCII码、表达式,语句,逗号表达式,三目运算,控制流。
3、函数意义,调用,声明,定义,函数形参与实参的关系,返回值、函数书写规则,函数名定义,函数调用返回的位置。
4、特殊函数用法:递归函数,回调函数,内联函数、变参函数。
5、数组定义、数组赋值、数组下标、整型数组、字符数组、指针数组、二维数组。
6、指针定义、指针赋值、指针解引用、空指针,野指针,通用类型指针,整型指针,字符指针,二级指针,数组指针,函数指针,const指针。
7、结构体定义、结构体变量、结构体指针、结构体变量与指针如何访问成员,如何计算结构体在内存中占用的字节数,结构体数组。
8、联合体使用、枚举类型,宏定义,头文件书写,条件编译,拆分多个.c文件,编译过程。
9、堆空间的申请与释放,字符串函数使用。

1)程序必须以main作为主函数的命名。
2)在程序中,main函数可以在任意的位置,都是被第一个执行的,并不是说第一个函数就会被第一个执行。
3)main函数有且仅有一个

写在main函数的函数头的前面即可。
一般而言,main函数返回值都是int类型,正常退出就返回0,异常退出就返回-1

在程序中,只要执行了return语句,那么就代表程序已经结束。

4、在linux下运行程序时,往往通过命令行给main函数传递参数。

1)程序中一定要写头文件吗?
不一定要。当我们在程序中,调用一个函数之前,必须先声明该函数,有些函数声明语句写在头文件中,当我们调用一些函数时不需要声明该函数,只需要包含这个函数对应的头文件就可以。换句话说,如果程序中没有调用任何的函数,也就是不需要声明任何的函数,头文件就不需要包含了。

对函数的声明函数,所以在调用函数之前一定要包含头文件。

3)函数对应的头文件在哪个,不需要背,只需要通过手册(新华字典)去查询即可。
如果说遇到函数的头文件不知道哪一个,怎么查?  -> printf()

命令公式: man 函数对应的手册数 函数名

1)每一个复合语句都需要进行缩进。

2)什么时候需要空行?
头文件与main函数之间。

2)编译过程做了什么事情?
其实就是检查这个C语言程序中语法是否正确。

编译完后,你可能会得到三种结果:
编译通过:不会出现任何的提示,代表编译通过,正常生成一个可执行程序。
编译警告:会出现提示,提示前面有一个明显warning,但是还是能够正常生成一个可执行程序。  ->例如: 没包头文件

   练习3: 写一个程序,实现无论输入多少个参数,都可以打印所有的参数。

数据类型描述了一个变量究竟存放着什么数据。

数据类型分为基本数据类型与非基本数据类型。
非基本数据类型:数组、指针、结构体

2、研究一下基本数据类型在内存中占用的空间问题?
例子:假设有一个整型变量,那么这个变量在内存中占用多少个字节?
看这个变量对应的数据类型是占用多少个字节。

 结论: 基本数据类型占用空间的大小由编译系统来决定的。

1、定义公式: 数据类型 变量名

2、内存分配原则?  -> 连续空闲不确定。
1)在分配内存时,内存地址一定是连续。
2)在分配内存时,一定是空闲。(之前的变量申请过的空间就不会再被申请到)
3)分配内存时,位置是不确定。

十、变量的赋值,作用域,生命周期。
使用"="来对变量进行赋值,"="的作用把"="右边的值赋值给"="左边的值。

2、变量的生命周期与作用域。
生命周期:这个变量从什么时候开始出现在内存空间到什么时候从内存空间中释放这个过程。
作用域:在程序中,这个变量能够作用到的地方。

1)什么是局部变量?什么是全局变量?
在程序函数体内部定义的变量就是局部变量,在函数体外定义的变量就是全局变量。

2)两者在内存空间中申请的位置区别?
局部变量申请的空间位置,一定在栈区。
全局变量未初始化过就是在bss段,已初始化过就是在data段。

局部变量在函数中定义时开始,在定义的函数返回时,就会释放这个空间。
全局变量一开始就会申请,等到程序结束才会释放。

局部变量:只能在定义该变量的那个函数中使用。
全局变量:整个程序中所有的函数都可以使用。

1、形式参数"int x"是属于局部变量还是全局变量?
属于局部变量,所以需要申请空间,还有就是在函数结束时会释放。

2、能不能在不同的函数中定义相同的变量名?

3、全局变量可以跟局部变量同名吗?
可以重名。如果重名,打印出来的值就是局部变量。

4、全局变量作用域只能往下,不能网上。

   练习4: 请求出以下程序的结果。  (考点: 局部变量的生命周期)

我要回帖

更多关于 两个printf只输出一个 的文章

 

随机推荐