printf为C语言中的库函数,需要包含头文件stdio.h,能够发送格式化输出到标准输出stdout,printf函数的声明如下。
printf函数的定义调用了fputs函数
我们在STM32单片机上面使用printf函数时,需要对fputs进行重定向,重定向为输出到串口,然后再通过串口转USB把数据输出到电脑上串口工具
u8 print_level=2;//打印开关
FILE __stdout;
//加入以下代码,支持printf函数
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
//定义_sys_exit(),以避免使用半主机模式
void _sys_exit(int x)
{
x = x;
}
void _ttywrch(int ch)
{
ch = ch;
}
//重定向fputs函数
int fputc(int ch, FILE *f)
{
USART_ClearFlag(USART6,USART_FLAG_TC);
USART_SendData(USART6, (unsigned char) ch);// USART1 ???? USART2 ?
while (!(USART6->SR & USART_FLAG_TXE));
return (ch);
}
名词解析
stdout fputs函数
要弄清什么是标准输入输出。首先需要弄懂什么是IO。
IO的I是Input的意思,O是output的意思。
意味着输入和输出。
更确切的含义是
I:从外部设备输入到内存
O:从内存输出到外部设备
而标准输入和标准输出是干什么的?它们是用于IO的。
那么它们属于IO的哪个部分?
内存?还是外部设备?
答案显然是外部设备(逻辑上的外部设备,为什么?接着看)。
更具体的含义?
在linux操作系统中,外部设备用什么表示?是用文件。
linux中一切设备皆是文件!
因此标准输入和输出更具体的含义是文件。
它们是哪两个文件?
它们是/dev/stdin这个文件和/dev/stdout这个文件。
也就是说所谓的标准输入和标准输出其实就是两个linux下的文件。
linux的文件类型有:
1、普通文件2、字符设备文件3、块设备文4、目录文件
5、链接文件6、管道文件7、套接字文件
思考一下?它们是什么文件?它们在/dev目录下,它们是设备文件吗?
那么所谓的从标准输入读是什么意思?
逻辑上来看:
就是打开/dev/stdin这个文件,然后把这个文件里的内容读进来。
输出到标准输出是什么意思?
逻辑上来看:
就是打开/dev/stdout这个文件,然后把内容输出到这个文件里去。
为什么是从逻辑上来看?因为它们不是设备文件!!!
所以它们不代表一个设备。linux里一切皆是文件,设备是文件,但是文件不一定是设备!
那它们是什么文件?他们是链接文件。(可以用ls -l /dev来查看 l开头的就是链接文件。)
什么是链接文件?文件内容是另一个文件的地址的文件称为链接文件。
因此,打开、读或者写 /dev/stdin和/dev/stdout 实际上是打开、读或者写这两个文件存放的地址对应的设备文件。
明白它们是链接文件不是设备文件有什么用?明白这一点才能知道重定向失效的原理
fputs函数
fputs()函数的第二个参数指明他要写入的文件。如果要在计算机显示器上打印,则使用stdout作为参数。与puts()函数不同,fputs()函数不会在待输出字符串末尾添加一个换行符。
#include <stdio.h>
#define LEN 14
int main(void){
char words[LEN];
puts("Enter a String");
fgets(words,LEN, stdin);
puts(words); //puts()函数会添加换行符\n
fputs(words, stdout);
return 0;
}
我们在写C程序时经常遇到printf(),fprintf(),perror(),这些东西到底有什么作用。说到这不得不提及stdin,stdout,stderr。想想,我们在用C去写文件时的操作,File fp=fopen(),这个fp就是我们向系统申请的,相当于一通往文件的通道。其实,stdin,stdout,stderr就是这个fp,不过他是随着计算机系统的开启默认打开的,其中0就是stdin,表示输入流,指从键盘输入,1代表stdout,2代表stderr,1,2默认是显示器。printf()其实就是向stdout中输出,等同于fprintf(stdout,“”),perror()其实就是向stderr中输出,相当于fprintf(stderr,“”),那到底stdout,和stderr有什么区别和作用呢?
我们在写程序时用printf()是为了我们能监控我们的程序运行状况,或者是说debug,如果我们的程序是一直运行,不停下来,我们不可能时刻盯着屏幕去看程序输出,这时我们就可以用文件重定向。将输出到一文件中,我们以后就可以看这文件就行。举个例子,test.c
<pre class="cpp" name="code">#include<stdio.h>
int main()
{
printf("stdout Helo World!!\n");
return 0;
}
编译过后,我们./test > test.txt(默认是将stdout里的内容重定向到文件中),这样就把test程序输出的内容输出到test.txt文件中。还有一种更明晰的写法./test 1>test.txt,这里的1就代表stdout。说到这你应该知道stderr该怎样处理了。再举个例子test.c:
#include<stdio.h>
int main()
{
printf("Stdout Helo World!!\n");
fprintf(stdout,"Stdout Hello World!!\n");
perror("Stderr Hello World!!\n");
fprintf(stderr,"Stderr Hello World!!\n");
return 0;
}
编译过后,./test,屏幕上是四条输出,如果./test > test.ext ,结果是屏幕上输出两条Stderr Hello World!!,Stdout Helo World!!在文件test.txt中,基于上面说的很容易理解现在的结果,于是我们可以随便处理我们想要的输出,例如:
./test 1>testout.txt 2>testerr.txt,我们将stdout输出到文件testout.txt中,将stderr输出到testerr.txt文件中;
./test 1>testout.txt ,将stdout输出到文件testout.txt 中,stderr输出到屏幕上;
./test 2>testerr.txt,将stderr输出到文件testerr.txt中,stdout输出到屏幕上;
./test > test.txt 2>&1,这是将stdout和stderr重定向到同一文件test.txt文件中。
如果我们不想看到输出内容,既不想在屏幕上看见,也不想重定向到文件中,别担心,万能的linux有解决办法,./test > /dev/zero 2>&1,这样就看不到任何输出了。
Note:stderr,和stdout还有重要一点区别,stderr是没有缓冲的,他立即输出,而stdout默认是行缓冲,也就是它遇到‘\n’,才向外输出内容,如果你想stdout也实时输出内容,那就在输出语句后加上fflush(stdout),这样就能达到实时输出的效果。
相关链接·:https://blog.csdn.net/wangyeqiang/article/details/38726433