解释一下printf()函数 fputs() 标准输入输出stdout stdin stderr

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

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学无止境2022

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值