Printf函数的实现

合集下载

printf函数的用法及注意事项 -回复

printf函数的用法及注意事项 -回复

printf函数的用法及注意事项-回复printf函数是C语言中常用的输出函数之一,用于向标准输出设备(通常是显示器)打印格式化的字符串。

本文将详细介绍printf函数的用法及注意事项。

一、基本用法printf函数的原型如下:int printf(const char *format, ...);它接收一个格式化的字符串format作为参数,该字符串可以包含普通字符和格式控制符。

格式控制符以开头,可用于指定输出的格式类型或占位符。

1. 普通字符输出普通字符会原样输出,不受格式控制符的影响。

我们可以直接在format 字符串中写入普通字符,例如:printf("Hello, World!");2. 格式控制符格式控制符用于指定输出的格式类型或占位符。

常用的格式控制符包括:- d或i:以十进制整数形式输出。

- u:以无符号十进制形式输出。

- f:以小数形式输出。

- c:以字符形式输出。

- s:以字符串形式输出。

- p:以指针的十六进制形式输出。

- :输出一个百分号。

具体的格式控制符及其使用方式可以参考C语言的相关教程。

3. 格式化输出printf函数的主要功能是格式化输出。

可以通过在字符串中插入格式控制符,并在其后传递相应的参数来输出不同类型的数据。

例如:int num = 10;printf("The number is d", num);输出结果为:The number is 104. 多个参数输出printf函数支持输出多个参数,通过在字符串中使用多个格式控制符,并按顺序传递相应的参数。

例如:int num1 = 10, num2 = 20;printf("The numbers are d and d", num1, num2);输出结果为:The numbers are 10 and 205. 返回值printf函数返回成功打印字符的个数(不包括字符串结尾的'\0'),若出现错误则返回负数。

Linux内核中的printf实现

Linux内核中的printf实现

Linux内核中的printf实现从main.c中的printf开始读这个函数。

⾸先看printf函数的定义:1 static int printf(const char *fmt, ...)2 {3 va_list args;4 int i;56 va_start(args, fmt);7 write(1,printbuf,i=vsprintf(printbuf, fmt, args));8 va_end(args);9 return i;10 }参数中明显采⽤了可变参数的定义,⽽在main.c函数的后⾯直接调⽤了printf函数,我们可以看下printf函数的参数是如何使⽤的。

1 printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS,2 NR_BUFFERS*BLOCK_SIZE);3 printf("Free mem: %d bytes\n\r",memory_end-main_memory_start);先来分析第⼀个printf调⽤:printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS, NR_BUFFERS*BLOCK_SIZE);可以看到*fmt等于"%d buffers = %d bytes buffer space\n\r”,是⼀个char 类型的指针,指向字符串的启始位置。

⽽可变的参数在这⾥是NR_BUFFERS和NR_BUFFERS*BLOCK_SIZE。

其中NR_BUFFERS在buffer.c中定义为缓冲区的页⾯⼤⼩,类型为int;BLOCK_SIZE在fs.h中的定义为#define BLOCK_SIZE 1024因此两个可变参数NR_BUFFERS和NR_BUFFERS*BLOCK_SIZE都为int类型;以前已经分析过可变参数的⼀系列实现函数va函数。

stm32_f103使用gcc编译的环境下printf打印函数的实现

stm32_f103使用gcc编译的环境下printf打印函数的实现

stm32_f103使⽤gcc编译的环境下printf打印函数的实现前记 gcc编译使⽤的printf打印函数需要的底层函数是和其他编译器不同的,以前的是⽆法使⽤的,这⾥有两种⽅法,⼀种是使⽤gcc库⾥⾯的printf函数,⾃⼰实现底层IO函数_write。

另外⼀种⽅法是⾃⼰定义 printf函数,这⾥给出两者实现⽅法及测试结果。

⽅法⼀ 假如要使⽤gcc库⾥⾯的printf函数,这⾥使⽤底层编译函数是_read()和_write(). 这⾥的read和write函数需要在system.c⾃⼰实现的,具体的实现⽅法如下所⽰:#include <errno.h>#include <sys/unistd.h> // STDOUT_FILENO, STDERR_FILENOint _write(int file, char *data, int len){if ((file != STDOUT_FILENO) && (file != STDERR_FILENO)){errno = EBADF;return -1;}// arbitrary timeout 1000HAL_StatusTypeDef status =HAL_UART_Transmit(&huart1, (uint8_t*)data, len, 1000);// return # of bytes written - as best we can tellreturn (status == HAL_OK ? len : 0);}⽅法⼆ 其实,说⽩了只要找到串⼝写函数,还有另外⼀种巧妙的⽅法,就是⾃制printf函数,不使⽤库⾥⾯的,代码如下所⽰:#include <stdio.h>#include <stdarg.h>#include <string.h>void vprint(const char *fmt, va_list argp){char string[200];if(0 < vsprintf(string,fmt,argp)) // build string{HAL_UART_Transmit(&huart1, (uint8_t*)string, strlen(string), 0xffffff); // send message via UART}}void my_printf(const char *fmt, ...) // custom printf() function{va_list argp;va_start(argp, fmt);vprint(fmt, argp);va_end(argp);}代码及运⾏结果 在代码中,这⾥分别给出两种⽅法的运⾏结果,如下所⽰:// uart initMX_DEBUG_USART_Init();/* 锟⽄拷锟接帮拷锟⽄拷锟⽄拷始锟⽄拷 */KEY_GPIO_Init();printf("test is init !\n\r");my_printf("test pressed my printf \n\r");/* 锟⽄拷锟⽄拷循锟⽄拷 */while (1){if(KEY1_StateRead()==KEY_DOWN){LED1_ON;printf("key1 pressed!\n\r");//my_printf("key1 pressed my printf \n\r"); }if(KEY2_StateRead()==KEY_DOWN){LED2_ON;printf("key2 pressed!\n\r");//my_printf("key2 pressed my printf \n\r"); }if(KEY3_StateRead()==KEY_DOWN){LED1_OFF;LED2_OFF;printf("key3 pressed!\n\r");//my_printf("key3 pressed my printf \n\r"); }}运⾏结果:参考⽬录 12。

c语言printf的用法详解

c语言printf的用法详解

c语言printf的用法详解printf函数是C语言中一个用于输出格式化字符串的函数。

其原型为:```cint printf(const char *format, ...);```该函数的主要作用是将格式化的字符串输出到标准输出(显示器)中。

下面是对printf函数的用法进行详细介绍:1.输出字符串:直接在format参数中写入要输出的字符串即可。

```cprintf("Hello, World!");```2.输出变量:使用格式控制符以及相应的参数,将变量的值输出。

```cint num = 10;printf("The number is %d", num);```在上述代码中,%d是格式控制符,用于输出整数类型的变量。

这样程序会将num的值替换%d,并输出到标准输出中。

3.输出多个变量:可以在format参数中使用多个格式控制符,并按照顺序传递相应的参数。

```cint x = 10;int y = 20;printf("The values are %d and %d", x, y);```4.格式控制符的使用:printf函数中的格式控制符用于指定输出参数的类型和格式。

常见的格式控制符包括:- %d:输出十进制整数- %ld:输出长整数- %f:输出浮点数- %c:输出字符- %s:输出字符串- %p:输出指针的地址还可以使用一些标识符来控制格式化输出的样式,例如:- %4d:输出四位整数,不足四位用空格填充- %06d:输出六位整数,不足六位用0填充- %.2f:输出浮点数并取两位小数5.转义字符的使用:printf函数支持使用转义字符来输出特殊字符,常见的转义字符包括:- \n:换行- \t:制表符- \\:反斜杠- \":双引号```cprintf("This\tis an example\n");```除了上述常见的用法,printf函数还可以通过控制修饰符控制输出的格式,例如输出的对齐方式,输出的颜色等等。

stm32重定向printf的原理

stm32重定向printf的原理

stm32重定向printf的原理在嵌入式系统中,调试是一个非常重要的环节。

而在调试过程中,printf函数是最常用的调试手段之一。

在STM32中,printf函数默认是向串口发送数据,但是有时候我们需要将printf函数的输出重定向到其他设备或者接口上。

本文将以STM32为例,介绍如何实现printf函数的重定向。

一、printf函数的实现原理printf函数是C语言标准库中的一个输出函数,其原型为:int printf(const char *format, ...);。

printf函数的作用是将格式化的字符串输出到标准输出设备上。

在STM32中,默认情况下,printf 函数的输出设备是串口。

其实现原理如下:1.调用stm32fxxx_hal_uart.c中的HAL_UART_Transmit函数,将格式化的字符串发送到串口中。

2.在stm32fxxx_hal_uart.c中,HAL_UART_Transmit函数通过USARTx_SR寄存器判断发送是否完成,如果未完成,则等待发送完成。

3.发送完成后,HAL_UART_Transmit函数返回。

二、printf函数的重定向在某些情况下,我们需要将printf函数的输出重定向到其他设备或接口上,例如:SD卡、LCD屏幕、WiFi模块等。

这时候,我们需要自定义一个输出函数,并将其与printf函数关联起来,实现printf函数的重定向。

下面,我们将以重定向printf函数输出到LCD 屏幕为例,介绍如何实现printf函数的重定向。

1.定义一个输出函数我们先定义一个输出函数,将其命名为LCD_Printf,其实现原理如下:void LCD_Printf(char *str){/* 将格式化的字符串输出到LCD屏幕上 */}2.将LCD_Printf函数与printf函数关联在main函数中,我们需要将LCD_Printf函数与printf函数关联起来,代码如下:/* 重定向printf函数 */int fputc(int ch, FILE *f){/* 将字符转换成字符串 */char str[2] = {0};str[0] = ch;/* 调用LCD_Printf函数,将字符输出到LCD屏幕上 */LCD_Printf(str);return ch;}在上述代码中,我们定义了一个名为fputc的函数,该函数的作用是将printf函数的输出重定向到LCD屏幕上。

printf源码解析

printf源码解析

printf源码解析printf是一种常见的输出函数,用于在控制台或终端打印文本或变量的值。

下面将对printf的源码进行解析,带您深入了解这个函数的工作原理。

printf函数是C语言中的标准库函数,其原型为:int printf(const char *format, ...)。

其中,format是一个字符串,用于指定输出的格式;...代表可变参数,表示可以传入任意个数的参数。

printf的实现主要分为两个步骤:格式字符串解析和参数输出。

在格式字符串解析阶段,printf会按照从左到右的顺序逐个处理format字符串中的字符。

当遇到普通字符时,printf会直接将其输出到控制台;当遇到格式控制符时,printf会根据指定的格式进行相应的输出。

格式控制符由百分号(%)和一个字符组成,用于指定输出的类型和格式。

常见的格式控制符有:%d(输出整数)、%f(输出浮点数)、%s(输出字符串)等。

通过格式控制符,我们可以控制输出的宽度、精度、对齐方式等。

在参数输出阶段,printf会根据格式控制符的类型,从可变参数中取出相应的值,并按照指定的格式进行输出。

当参数的类型与格式控制符不匹配时,printf会进行类型转换。

除了普通的格式控制符外,printf还支持一些特殊的转义序列,用于输出一些特殊的字符,例如换行符(\n)、制表符(\t)等。

总结一下,printf函数通过解析格式字符串和处理可变参数,实现了将数据以指定的格式输出到控制台的功能。

它是C语言中非常常用的一个函数,广泛应用于各种编程场景中。

通过对printf源码的解析,我们深入了解了这个函数的工作原理。

希望本文对您有所帮助,谢谢阅读!。

c++ printf 基本用法举例

c++ printf 基本用法举例

c++ printf 基本用法举例printf是C语言中的一个重要函数,用于在控制台上输出格式化的字符串。

通过printf函数,我们可以方便地输出各种类型的数据,包括整数、浮点数、字符、字符串等。

下面我们将介绍printf函数的常用用法和举例。

一、printf函数的定义和基本用法printf函数的定义格式为:printf(“格式控制符”,“输出参数1”,“输出参数2”...)。

其中,“格式控制符”用于指定输出的格式和类型,而“输出参数”则是需要输出的数据。

基本用法示例:```c#include<stdio.h>intmain(){printf("Hello,world!\n");printf("Thevalueofxis:%d\n",x);printf("Theresultis:%.2f\n",result);return0;}```上述示例中,我们输出了三个字符串和一个浮点数。

第一个字符串直接输出,后面两个字符串使用了格式控制符。

%d表示输出一个整数,%.2f表示输出一个浮点数并保留两位小数。

二、printf函数的常用格式控制符printf函数支持多种格式控制符,包括:%d、%f、%s、\n、\%、\%、^等。

下面我们将介绍一些常用的格式控制符及其用法。

1.%d:输出一个整数。

2.%f:输出一个浮点数。

3.%s:输出一个字符串。

4.\n:换行符。

5.\%:转义字符,输出一个百分号%。

6.\:转义字符,输出一个反斜杠\。

7.^:输出上箭头字符^。

常用格式控制符用法示例:```c#include<stdio.h>intmain(){inta=10;floatb=20.5;charc[]="Hello,world!";printf("a=%d\n",a);//输出整数a的值。

printf("b=%.2f\n",b);//输出浮点数b的值并保留两位小数。

单片机C语言实现printf

单片机C语言实现printf

单片机串口实现printf函数背景叙述:在初学C语言时,利用printf函数向屏幕上输出字符,非常的好用和方便。

学会单片机以后,尤其在学会串口通信之后,通过单片机的串口向PC机发送数据,怎么实现printf函数的功能。

对于学习单片机来说,如果没有仿真器,出错误的时候不好找,只能用最笨的办法,使用printf函数,可是在KEIL里面使用printf却不像VC里面那么简单,因为其发送和硬件是有关系的。

所以今天就简单来说说怎么在51单片机中使用"printf"函数:包括使用自带的printf函数和自己动手写一个printf函数功能描述:通过printf函数向串口发送数据,显示在终端或者串口助手上Proteus中串口终端的介绍1、连接方法如下所示2、串口的配置尤其注意配置的波特率一定要和程序代码中所写的一样(否则会造成无法显示字符)数据位停止位奇偶校验位极性(这些属性基本上是默认的配置)3、串口终端的使用proteus virtual terminal 使用注意事项a. virtual terminal 默认显示字符,如果单片机发送的是非显示字符,则虚拟终端不会显示,会导致用户认为通讯未通。

运行程序,在虚拟终端窗口里面点击右键,在弹出菜单里面:选HEX DISPLAY MODE,则显示按十六进制显示,能显示所有字符。

b.virtual terminal 默认情况下不显示回显字符,运行程序,在虚拟终端窗口里面点击右键,在弹出菜单里面:选Echo Typed Characters 显示回显字符c.virtual terminal 和模拟物理串口COMPIM不能同时使用,同时使用会发生相互影响。

d. 启动仿真后可以右键单击终端,最后一栏打开和关闭串口显示终端源程序直接使用系统自带的printf函数:特别注意需要置位TI=1,否则是无法发送的,程序如下(此程序在proteus终端上不能显示汉字,但在串口调试助手上可以)/******decription******************利用printf函数向串口打印信息51单片机晶振频率11.0592MHZ串口通信波特率9600bps利用printf函数TI初始值必须置1***********************************//*******includes file*************/#include<reg51.h>#include<intrins.h>#include<string.h>#include<stdio.h>#define uchar unsigned char#define uint unsigned intvoid delay_1ms(uint z){uint x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}void uart_init(void)TMOD=0x20; //定时计数器1,工作方式2TH1=0xFD; //设置波特率9600TL1=0xFD;TR1=1;SCON=0x50;PCON=0x00;EA=1;ES=1;TI=1; //若利用printf函数则TI初始值必须置1 }void main(){uart_init();while(1){// SBUF = 'H';// while(TI==0);// TI=0;printf("i am herro!\n\r");delay_1ms(1000);if(ff){ff=0;printf("%c",num);}}}void ser_interrupt() interrupt 4{if(RI==1){ES=0;RI=0;num=SBUF;ES=1;ff=1;}}4.编写自己的printf函数(这个函数不能再proteus中仿真,但实际中可以使用)a.预备知识①C语言函数:vsprintf,其原型为int vsprintf(char *string, char *format, va_list param);,作用为将param按格式format写入字符串string中,因此他可以用于将任何格式数据转化为字符串数据,比如把整数97转化为ASCII码的97的程序就像下面这样vsprintf(string,"%d",97),当然还有一点需要注意:在keil里面使用sprintf需要包含stdio.h这个头文件(当然这里也可以使用sprintf,作用完全差不多,只需要稍加修改即可,不多介绍)。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

的示例( ● printf的示例(四) 的示例
自己写一个printf: : 自己写一个
case 's': { char *p = va_arg(ap, char *); fputs(p,stdout); break; } default: putchar(ch); }//switch结束 结束 }//while 结束 void main() va_end(ap); { }//myprintf结束 结束 myprintf("c\ts\n",'A',"hello"); }
( ap = (va_list)& format+ _INTSIZEOF(format) )
#define va_arg(va_list ap,type)
( *(type*)((ap += _INTSIZEOF(type)) -_INTSIZEOF(type)) )
#define va_end(va_list ap) ( ap = (va_list)0 )
以下为VC++中stdarg.h里x86平台的宏定义 ● 以下为 中 里 平台的宏定义
typedef char * va_list; #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) #define va_start(va_list ap, format)
● 栈示意图
高地址
… … … 第n个参数 个参数 第n-1个参数 个参数
函数返回地址
可变参数列表 第一个可变参 最后一个固定参 va_arg后ap指向 后 指向 va_start后ap指向 后 指向
低地址

format
的示例( ● printf的示例(三) 的示例
自己写一个printf: : 自己写一个
printf的定义
● printf的声明 的声明 int _cdecl printf(const char* format, …); _cdecl是C和C++程序的缺省调用方式
printf的实现
●_CDEDL调用约定 调用约定
1.参数从右到左依次入栈 参数从右到左依次入栈 2.调用者负责清理堆栈 调用者负责清理堆栈 3.参数的数量类型不会导致编译阶段的错误 参=3; printf("%d",a,b); ( " ); 2. double a=2.345; printf("%d",a); 3. printf("%d"); 4. printf("asd",a);
printf实现原理
★要解决的问题 1.怎么告诉 怎么告诉printf我们会传入几个参 怎么告诉 我们会传入几个参 数 2.printf怎么去访问这些参数 怎么去访问这些参数 3.函数调用完成后,系统怎么把参数 函数调用完成后, 函数调用完成后 从传递用的堆栈中释放
的示例( ● printf的示例(一) 的示例 int __cdecl printf ( const char *format, ... ) { va_list ap; int buffing; int retval; va_start(ap, format); _ASSERTE(format != NULL); _lock_str2(1, stdout); buffing =_stbuf(stdout); retval = _output(stdout,format,ap); _ftbuf(buffing, stdout); _unlock_str2(1, stdout); return(retval); }
C语言可变参函数 语言可变参函数
printf
0724 白雪
printf语法回顾
● 第一段接触的C语言代码 #include<stdio.h> void main() { printf("This is a C program.\n "); }
例1. #define PRICE 30 #include <stdio.h> void main() { int num,total; num=10; total=num*PRICE; printf("total=%d\n",total); }
的示例( ● printf的示例(二) 的示例 函数实现流程: 函数实现流程: va_start(ap, format); retval = _output(stdout,format,ap); 01 while(format[n]){ 02 if (format[n] == "%"){ 03 n++; 04 switch(format[n]){ 05 case 'c': 06 ....... 为例: 以case 'c'为例: 为例 07 case 'd': 08 ....... case 'c': 09 ....... putchar(va_arg(ap, unsigned char)); 10 }//switch cnt_printed_chars++; 11 }//if break; 12}//while 13 va_end(ap);
printf 小结
可变参函数实现总结: ● 可变参函数实现总结: 1.va_系列宏 系列宏 2.堆栈 堆栈 3.所有类型固定的参数都必须出现在参 所有类型固定的参数都必须出现在参 数列表的开始
Thank You! !
0724
白雪

例2. printf("%d,%d\n",sizeof(short),sizeof(int)); 例3. float a,b,c; a=3.141592612; b=2.76543; c=3.456732; printf("%f,%f,%f\n",a,b,c);
例4. char c1,c2,c3,c4; c1='a'; c2='b'; c3='c'; c4='d'; printf("%c,%c,%c,%c\n",c1,c2,c3,c4); 注意: 注意:
#include <stdio.h> #include <stdarg.h> void myprintf(const char *format, ...) { va_list ap; char ch; va_start(ap, format); while(ch = *format++) { switch(c) { case 'c': { char ch1 = va_arg(ap, char); putchar(ch1); break; }
相关文档
最新文档