《玩透嵌入式C的角角落落》深入分析sprintf和printf函数

Posted 嵌入式历练者

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《玩透嵌入式C的角角落落》深入分析sprintf和printf函数相关的知识,希望对你有一定的参考价值。

//只节选部分代码说明
  char txt[32];
  unsigned int Distance=0;
  while(1) 	
				
		if(timecount>=50)                   //500ms采集一次距离
		
			if(CheckChanel[0]==1) 
			
				Distance = Read_Distance();
				if(Distance<1000)
				
				  Gui_DrawFont_GBK16(100,25,BLUE,GRAY0,"  ");			
						
                sprintf(txt, "%d", Distance);
		        Gui_DrawFont_GBK16(85,25,BLUE,GRAY0,txt); //前两个参数是坐标,显示内容颜色,背景色,数据		
			
			timecount=0;
			LED1=~LED1;
			
			

    最近项目用到了sprintf函数调试程序,故想写下一篇博客来分析下sprintf函数,其函数原型为

function prototype
int sprintf(char *buffer ,const char *format, [argument]…);

    看到const和指针的声明,我想简单提下几种声明的区别,在经典书《C专家编程》有对恐怖的C语言声明做过解释

/*第1,2种情况,指针所指向的对象是只读的
  当然对象和指针有可能都是只读的*/
const char *format; 
char const *format;

char * const format; //第3种情况指针是只读的

/*下面两种方式的声明都能做到这一点--->对象和指针都是只读的*/
const char * const format; 
char const * const format;

小技巧------>Keil5中鼠标放在调用函数名处不动,即可显示出该函数的函数原型

玩透sprintf和printf函数

  • sprintf是一个变参函数,和printf的功能差不多,只是第一个参数是指定把输出的内容输出到“什么地方

  •   //网友的例子
      例:将”test 1 2”写入数组s中
      #include<stdio.h>
      int main(int argc, char *avgv[])
      
        char s[40];
        /*第一个参数就是指向要写入的那个字符串的指针,剩下的就和printf()一样了*/
        sprintf(s,"%s%d%c","test",1,'2'); 
          
       /*你可以比较一下,这是向屏幕输入*/
        printf("%s%d%c","test",1,'2');
        return 0;
      
    

    网上找的例子是在标准C语言在PC端调试,最常用的printf打印函数,会直接打印到PC端命令行窗口上,而在单片机调试中,我们常用printf打印有用信息来调试我们的程序,但是却不能直接使用,究其原因,在于标准C语言printf函数的底层实现的机制,已经规定输出流输出到PC端的显示器(或者是现编译器的命令行窗口)。

    这也是单片机调试时,为什么要对printf函数进行重定向的原因,所谓重定向,这里涉及流的概念,即“重新定义信息流的流动方向‘’——我从哪里来,又要到哪里去”。即要实现在串口或者LCD上显示,必须重定义标准库函数里面调用的输出设备定义的相关函数。

    扩展一下:在C++中,包含了标准库#include ,其中stream英文表示流的意思,iostream库是istream(输入流)和ostream(输出流)组合而成,术语流极其想表达出字符随着时间顺序生成和消失的特点。

	#include<iostream>
	int main()
		std::cout<<"hello,world";
		return 0;
	

    接下来,我们又回到sprintf函数,sprintf在参数列表中多了一个“具体输出到什么地方”的参数。与printf函数不同在于转化后的结果没有送往标准输出设备,而是存放在由指针变量buffer指定的字符缓冲区,这个缓冲区可以是个字符数组。
    例如,将浮点数3.14转化成长度为4,含2位小数的字符串,存储在字符缓冲区buffer中,代码如下:

sprintf(buffer,"%4.2f",3.14)

项目中sprintf的用法

#include "stdio.h"   //为了解除sprintf警告
unsigned int Distance=0;
char txt[32];
/*这个Distance在上文环境中被定义为距离变量,
测距传感器采集的距离值存储在此变量内。*/
sprintf(txt, "%d", Distance);
//将Distance变量内容按照%d格式放在txt数组中,来方便显示

汇总sprintf三大常犯错误:
1.给定的缓冲区溢出,如给的数组的长度太短而导致溢出
2.和printf搞混,忘记第一个参数。
3.对应的格式化字符串用错,参数可以有很多个

char s[40];
sprintf(s,"%s%d%c","test",1,'2'); 
/*这里将内容("test",1,'2')按照指定的格式("%s%d%c")输出
到这个地方(s)*/

    sprintf函数功能强大,可以方便的完成各类数据类型的转换,但会占用相当大的代码空间。

以上是关于《玩透嵌入式C的角角落落》深入分析sprintf和printf函数的主要内容,如果未能解决你的问题,请参考以下文章

面试复盘-生活不就是起起落落落落落吗?

面试复盘-生活不就是起起落落落落落吗?

涨知识,全面深入了解嵌入式C语言可靠性设计

嵌入式Linux从入门到精通之第四节:深入指针分析

嵌入式Linux从入门到精通之第四节:深入指针分析

玩透指针系列——茅塞顿开,原来这就是指针!