精华内容
下载资源
问答
  • 2018-10-24 20:59:15

    函数名:freopen
    函数,以指定模式重新指定到另一个文件。模式用于指定新文件的访问方式。
    头文件:stdio.h
    C89函数声明:

    FILE *freopen( const char *filename, const char *mode, FILE *stream );
    

    C99函数声明:

    FILE *freopen(const char * restrict filename, const char * restrict mode, FILE * restrict stream);
    

    形参说明:

    filename:需要重定向到的文件名或文件路径。
    mode:代表文件访问权限的字符串。例如,"r"表示“只读访问”、"w"表示“只写访问”、"a"表示“追加写入”。
    stream:需要被重定向的文件流。
    返回值:如果成功,则返回该指向该输出流的文件指针,否则返回为NULL。
    

    eg:

    freopen("../1.in","r",stdin);
    freopen("../1.out","r",stdout);
    

    1.代表输入流 变为从指定文件输入
    2.代表输出流 变为输出道指定文件内
    默认情况下cin cout与之保持一致

    简单写东西的话 相对于fscanf() 和fprintf() 还是比较方便的
    但是不能替代

    更多相关内容
  • 最近遇到需要MCU输出数字的问题,而STM32的串口输出的是字符型,最先想到的方法是将整型数据转换为字符型输出,C库函数中提供了相关的函数
  • printf函数重定向实现(2014-09-05 13:50:29)标签:佛学在嵌入式系统中,串口常用来辅助调试输出一些调试信息。所以有必要实现串口的格式化输出功能,这可以由3种方法实现(就我目所知).1)使用系统库函数printf(),这...

    printf函数的重定向实现

    (2014-09-05 13:50:29)

    标签:

    佛学

    在嵌入式系统中,串口常用来辅助调试输出一些调试信息。所以有必要实现串口的格式化输出功能,这可以由3种方法实现(就我目所知).

    1)使用系统库函数printf(),这就需要重载输入,输出函数int fputc(int ch, FILE *f);int fgetc(FILE *f).

    2)使用sprintf()函数将数据格式化到数组,然后将数组输出.也可以使用vsprintf().

    3)自己写类似printf()函数.

    这里假设已经编写了基本的输入输出函数如下:

    int sendchar(int ch); // 发送字符

    int sendstr(char *str);//发送字符窜

    int getkey(void); // 接受字符

    1)第一种方法的实现

    比较简单只要实现以下2个函数:

    int fputc(int ch, FILE *f) {

    return (sendchar(ch));

    }

    int fgetc(FILE *f) {

    return (getkey());

    }

    使用方法:

    #include

    void main()

    {

    ...

    printf("%s,%d,%x","hello",0x10,0x10);//输出: hello,16,10

    ...

    }

    2)第二种方法的实现

    void Uart_Printf(const char *fmt,...)

    {

    va_list ap;

    char string[256];

    va_start(ap,fmt);

    vsprintf(string,fmt,ap);

    Uart_SendString(string);

    va_end(ap);

    }

    3)第三种方法的实现

    int myprintf (const char* str,...)

    {

    va_list arp;

    uint8 c, f, r;

    ULONG val;

    char s[16];

    int i, w, res, cc;

    va_start(arp, str);

    for (cc = res = 0; cc != EOF; res += cc) {

    c = *str++;

    if (c == 0) break;

    if (c != '%') {

    sendchar(c);

    cc=1; //cc保存当前循环发送的数据

    continue;

    }

    w = f = 0; //f为格式 ,w为宽度

    c = *str++;

    if (c == '0') {

    f = 1;

    c = *str++; //等于c = *(str++);先取值,最后str++ ;f的第0位代表用0填充对齐 c = *(str++);

    }

    while (c >= '0' && c <= '9') {

    w = w * 10 + (c - '0'); //计算对齐宽度

    c = *str++;

    }

    if (c == 'l' || c=='L') {

    f |= 2; c = *str++; //f的第二位代表Long前缀

    }

    if (c == 's' || c == 'S') {

    cc = sendstr(va_arg(arp, char*));//发送字符窜,cc=放松字符个数

    continue;

    }

    if (c == 'c' || c == 'C') {

    sendchar(va_arg(arp, int)); //char 改 int

    cc = 1;

    continue;

    }

    r = 0;

    if (c == 'd' || c =='D') r = 10; //r代表进制

    if (c == 'u' || c == 'U') r = 10;

    if (c == 'X' || c == 'x') r = 16;

    if (r == 0) break;

    if (f & 2) {

    val = (ULONG)va_arg(arp, long); //获取Long型参数,arp指向下一个参数

    } else { //没有'l'标志

    val = (c == 'd') ? (ULONG)(long)va_arg(arp, int) : (ULONG)va_arg(arp, unsigned int);

    //不管是int 还是 unsigned int 都转化为 unsigned long

    }

    if (c == 'd') {//如果是'd'前缀就要判断刚获取的参数是正还是付

    if (val >= 0x80000000) { //最高位为1说明是负的

    val = 0 - val;

    f |= 4;//f的第三位代表"+/-"

    }

    }

    i = sizeof(s) - 1; s[i] = 0;//i=15

    do {

    c = (uint8)(val % r + '0');//r代表进制

    if (c > '9') c += 7; //对于16进制 转换到对应的'abc...'需要+7 :'\58'+7='65'='a'

    s[--i] = c; //从后面开始保存

    val /= r;

    } while (i && val);

    if (i && (f & 4)) s[--i] = '-';//是负数添加'-'号

    w = sizeof(s) - 1 - w;

    while (i && i > w) s[--i] = (f & 1) ? '0' : ' ';

    cc = sendstr(&s[i]);

    }

    va_end(arp);

    return (cc == EOF) ? cc : res;

    }

    变参数表的调用形式以及原理:

    参数在内存中存放格式:大多数情况堆栈是从高到低生长,函数参数入栈时后面的参数先入栈。参数弹出顺序与入栈顺序相反。

    举个例子如下:

    void func(int x, float y, char z);

    那么,调用函数的时候,实参 char z 先进栈,然后是 float y,最后是 int x,因此在内存中变量的存放次序是 x->y->z,因此,从理论上说,我们只要探测到任意一个变量的地址,并且知道其他变量的类型,通过指针移位运算,则总可以顺藤摸瓜找到其他的输入变量。

    下面是MDK 里面重要的几个宏定义如下:

    typedef struct __va_list { void *__ap; } va_list;

    #define va_arg(ap, type) __va_arg(ap, type)

    #define va_end(ap) ((void)(ap))

    使用方法:

    在调用参数表之前,定义一个 va_list 类型的变量,(假设va_list 类型变量被定义为ap);

    然后应该对ap 进行初始化,让它指向可变参数表里面的第一个参数,这是通过 va_start 来实现的,第一个参数是 ap 本身,第二个参数是在变参表前面紧挨着的一个变量,即“...”之前的那个参数;

    然后是获取参数,调用va_arg,它的第一个参数是ap,第二个参数是要获取的参数的指定类型,然后返回这个指定类型的值,并且把 ap 的位置指向变参表的下一个变量位置;

    获取所有的参数之后,我们有必要将这个 ap 指针关掉,以免发生危险,方法是调用 va_end,他是输入的参数 ap 置为 NULL,应该养成获取完参数表之后关闭指针的习惯。

    va_list的"等价"替换:

    va_list arp; <==> {char *arp = 0;}

    va_start(arp, str);<==>{ arp = (char *)&str; arp += sizeof(str); }

    sendstr(va_arg(arp, type));<==> { sendstr( *(type*)arp); arp += sizeof(type);}

    va_end(arp); <==>{ arp = 0;}

    因此上述函数可以改为:

    int myprintf ( const char* str, ...)

    {

    //va_list arp;

    char *arp = 0;

    uint8 c, f, r;

    ULONG val;

    char s[16];

    int i, w, res, cc;

    //va_start(arp, str);

    arp = (char *)&str;

    arp += sizeof(str);

    for (cc = res = 0; cc != EOF; res += cc) {

    c = *str++;

    if (c == 0) break;

    if (c != '%') {

    sendchar(c);

    cc=1; //cc保存当前循环发送的数据

    continue;

    }

    w = f = 0; //f为格式 ,w为宽度

    c = *str++;

    if (c == '0') {

    f = 1;

    c = *str++; //等于c = *(str++);先取值,最后str++ ;f的第0位代表用0填充对齐 c = *(str++);

    }

    while (c >= '0' && c <= '9') {

    w = w * 10 + (c - '0'); //计算对齐宽度

    c = *str++;

    }

    if (c == 'l' || c=='L') {

    f |= 2; c = *str++; //f的第二位代表Long前缀

    }

    if (c == 's' || c == 'S') {

    //cc = sendstr(va_arg(arp, char*));//发送字符窜,cc=放松字符个数

    sendstr( *(char **)arp);

    arp += sizeof(char *);

    continue;

    }

    if (c == 'c' || c == 'C') {

    // sendchar(va_arg(arp, int)); //char 改 int

    sendchar(*((int *)arp));

    arp += sizeof(int);

    cc = 1;

    continue;

    }

    r = 0;

    if (c == 'd' || c =='D') r = 10; //r代表进制

    if (c == 'u' || c == 'U') r = 10;

    if (c == 'X' || c == 'x') r = 16;

    if (r == 0) break;

    if (f & 2) {

    //val = (ULONG)va_arg(arp, long); //获取Long型参数,arp指向下一个参数

    val=(ULONG)(*((long *)arp));

    arp += sizeof(ULONG);

    } else { //没有'l'标志

    val = (c == 'd') ? (ULONG)(long)va_arg(arp, int) : (ULONG)va_arg(arp, unsigned int);

    //不管是int 还是 unsigned int 都转化为 unsigned long

    }

    if (c == 'd') {//如果是'd'前缀就要判断刚获取的参数是正还是付

    if (val >= 0x80000000) { //最高位为1说明是负的

    val = 0 - val;

    f |= 4;//f的第三位代表"+/-"

    }

    }

    i = sizeof(s) - 1; s[i] = 0;//i=15

    do {

    c = (uint8)(val % r + '0');//r代表进制

    if (c > '9') c += 7; //对于16进制 转换到对应的'abc...'需要+7 :'\58'+7='65'='a'

    s[--i] = c; //从后面开始保存

    val /= r;

    } while (i && val);

    if (i && (f & 4)) s[--i] = '-';//是负数添加'-'号

    w = sizeof(s) - 1 - w;

    while (i && i > w) s[--i] = (f & 1) ? '0' : ' ';

    cc = sendstr(&s[i]);

    }

    //va_end(arp);

    arp = 0;

    return (cc == EOF) ? cc : res;

    }

    分享:

    a4c26d1e5885305701be709a3d33442f.png喜欢

    0

    a4c26d1e5885305701be709a3d33442f.png赠金笔

    加载中,请稍候......

    评论加载中,请稍候...

    发评论

    登录名: 密码: 找回密码 注册记住登录状态

    昵   称:

    评论并转载此博文

    a4c26d1e5885305701be709a3d33442f.png

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

    展开全文
  • 一、32位系统下函数重定向说明 原理:找到想要hook的函数在内存中的地址,将函数的头几个字节保存在自己的内存中,用jump cpu指令改写函数的头几个字节,该指令会转移到替换函数的内存地址,(替换函数必修和被hook...
  • #include 头文件#ifdef __GNUC__#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)#else#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)#endifPUTCHAR_PROTOTYPE{USART_SendData(EVAL_COM1, (uint8_t) ch)...

    #include  头文件

    #ifdef __GNUC__

    #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)

    #else

    #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)

    #endif

    PUTCHAR_PROTOTYPE

    {

    USART_SendData(EVAL_COM1, (uint8_t) ch);

    while (USART_GetFlagStatus(EVAL_COM1, USART_FLAG_TC) == RESET)

    {}

    return ch;

    }

    定义了以上的

    然后就可以调用 printf("\n\rPlease enter valid number between 0

    and 9");

    ===============================================================

    C库函数重定向

    用户能定义自己的C语言库函数,连接器在连接时自动使用这些新的功能函

    数。这个过程叫做重定向C语言库函数,如下图所示。

    举例来说,用户有一个I/O设备(如UART)。本来库函数fputc()是把字符输出

    到调试器控制窗口中去的,但用户把输出设备改成了UART端口,这样一来,

    所有基于fputc()函数的printf()系列函数输出都被重定向到UART端口上去

    了。

    下面是实现fputc()重定向的一个例子:

    extern void sendchar(char*ch);

    int fputc(intch,FILE*f)

    char tempch=ch;

    sendchar(&tempch);

    return ch;

    }这个例子简单地将输入字符重新定向到另一个函数sendchar(),sendchar()

    假定是个另外定义的串口输出函数。在这里,fputc()就似乎目标硬件和标

    准C库函数之间的一个抽象层。

    这里是用来进行printf的重定向的,就是我们像用我们C语言标准库的的printf一样来适用prinf来作为串口的输出。

    展开全文
  • C语言重定向

    万次阅读 多人点赞 2017-03-14 16:07:06
    近段时间,又把C primer plus第五版翻了一下,查看以前由于不理解而跳过的地方,现在来看时,结合在其他书上看到的东西(在linux书上看到关于重定向的使用),发现自己居然能够理解了。 Unix、Linux和当前的DOS版本...

    近段时间,又把C primer plus第五版翻了一下,查看以前由于不理解而跳过的地方,现在来看时,结合在其他书上看到的东西(在linux书上看到关于重定向的使用),发现自己居然能够理解了。
    Unix、Linux和当前的DOS版本都能够重定向输入和输出。输入重定向可以使程序能够使用文件代替键盘作为输入,输出重定向则使程序能够使用文件代替屏幕作为输出。
    一、 输入重定向
    输入重定向即用文本文件代替键盘当作程序的输入。 ‘ < ‘ 符号是Unix、Linux和DOS的重定向运算符。该运算把文件和stdin流关联起来,将该文件的内容引导至程序。程序本身并不知道(或关心)输入是来自文件而不是来自键盘。C将文件和I/O设备置于相同的地位,所以现在这个文件就是I/O设备。我们来写个程序感受一下到底是怎么用的。首先编写一个Reput.c文件,代码如下所示。

    #include<stdio.h>
    int main()
    {
        char ch;
        while ((ch = getchar())!= EOF )     //读取输入字符
        {
            putchar(ch);       //输出字符
        }
        putchar('\n');
        return 0;
    }
    

    编译程序得到一个.exe可执行文件。DOS下使用cmd打开命令行,进入生成的.exe所在目录。输入命令: Reput.exe < test.txt。如图1所示。 test.txt里的内容如图2所示被印出来。

    图1 重定向输入


    图2 test.txt的内容
    重定向的文件可以自己选择,是文本文件即可。文本文件是包含文本的文件,即在该文件的中数据以人类可读的字符形式存储,如它可以是一篇短文或用C编写的程序。而包含机器语言指令的文件就不是文本文件。

    二、 重定向输出
    输出重定向就是用文本文件代替屏幕当作程序的输出。’ > ’运算符是另一个重定向运算符。假设我们要将键盘输入的数据发送至一个名为test1.txt的文件。通过下面这条语句就可以完成:Reput.exe > test1.txt。该运算符会导致建立一个名为test1.txt的新文件供我们使用,然后将Reput.exe的输出(也就是说,我们嵌入的字符的副本)重定向到该文件。该重定向将stdout从显示设备(屏幕)重定向到test1.txt文件。如果您已经有一个名为test1.txt的文件,则通常会删除该文件然后用新的文件代替。操作过程如图3所示,按Ctrl+Z(DOS中)结束输入。此时,我们可以通过查看到有个test1的txt文本,打开如图4所示。

    图3 重定向输出


    图4 test1.txt的内容
    此时我们也可以借用上面说过的重定向输入来查看test1.txt的内容。

    补充:
    1、重定向运算符是将一个可执行程序与一个数据文件连接起来,该运算符不能用于一个数据文件与另外一个数据文件的连接,也不能用于一个程序和另一个程序的连接。
    2、使用这些运算符时,输入不能来自一个以上的文件,输出也不能定向至一个以上的文件。
    3、’>>’运算符用累加的方法将数据输出到指定的文件上,不会覆盖已有的数据。

    展开全文
  • printf()函数重定向

    2021-01-28 16:05:34
    关于printf函数在单片机中的使用 MicroLib是缺省c库的备选库,...重定向fputc函数 在MicroLib的stdio.h中,fputc()函数的原型为: int fputc(int ch, FILE *stream) 函数含义:将字符ch打印到文件指针stream所指向的文
  • 1. C语言是没有I/O的语言C语言本身就是没有I/O能力的语言,是依靠函数模块来完成的。如printf()就是一个I/O函数,在编译时,编译器并不编译printf()函数,而把他留在链接(link)阶段由链接器来处理。这样做的优点是:...
  • 在前面学习了STM32的串口编程,通过USART1向计算机的串口调试助手打印数据,或者接收计算机串口调试助手的数据,接下来我们可以实现STM32工程上的printf()函数了,方便用于程序开发中调试信息的打印。 ...
  • C程序中要包含stdio.h头文件才可以直接使用putchar()和getchar()函数。(其实这两者都不是真正的函数,它们被定义为预处理器处理的宏) ANSI C 和后续的C标准都规定输入是缓冲的。缓冲区的大小取决于系统,常见大小...
  • 函数定义:FILE *freopen( const char *path, const char *mode, FILE *stream ); 头文件:<stdio.h> 参数说明: path: 文件名,用于存储输入输出的自定义文件名。 mode: 文件打开的模式。和fopen中的模式...
  • stm32f103串口printf,scanf函数串口重定向stm32f103串口printf,scanf函数串口重定向串口重定向的步骤:首先配置USART串口(初始化这些)重定向函数首先配置USART串口(初始化这些)先看代码uart.c中#include #include ...
  • 1.2 重定向fputc函数 在MicroLib的stdio.h中,fputc()函数的原型为: int fputc(int ch, FILE* stream) 此函数原本是将字符ch打印到文件指针stream所指向的文件流去的,现在我们不需要打印到文件流,而是打印到串口...
  • C语言重定向fputc函数

    千次阅读 多人点赞 2018-03-26 19:43:18
    链接器检查到用户编写了与C库函数相同名字的函数时,优先调用用户编写函数,这样就可实现重定向 重定向printf()函数 需重写fputc()这个c标准库函数(printf()在c标准库函数实质是一个宏,实际是调用fputc()函数...
  • 在Linux上学习STM32有一段时间了,其中困扰我的就是在Linux系统上的串口调试助手和USART这节的重定向c库函数printf到串口了。(因为我用的是gcc) 串口方面曾用过minicom,但感觉不是太方便,又因为运行minicom后,...
  • 来源:http://yonghan.blog.sohu.com/94105721.htmldup和dup2函数的作用#include...//新文件描述符复制filedes,并且将filedes2值作为新文件描述符的值//dup函数的作用:复制一个现有的句柄,产生一个与“源句柄特性...
  • 1、基本概念a、 I/O重定向通常与 FD有关,shell的FD通常为10个,即 0~9;b、常用FD有3个,为0(stdin,标准输入)、1(stdout,标准输出)、2(stderr,标准错误输出),默认与keyboard、monitor、monitor有关;c、 用 &...
  • 输入输出重定向与fopen函数——C语言进阶

    千次阅读 多人点赞 2021-12-13 14:01:56
    浅谈 fopen与 freopen 函数
  • 在STM32串口通信程序中使用printf()函数发送数据非常方便,但是需要先进行简单...第2步:在main.c文件中重定义fput()这个C标准库函数(因为printf()在C标准库函数中实质上是一个宏,要调用到fputc()这个函数);
  • 1原型重定向概念 概念:改变内置原型指向 使用场景:批量给内置原型上增加属性和方法 存在的问题: 重新定向的对象中没有constructor ...// 向原型上扩展 A B C D 四方法 Func.prototype.A = functi...
  • C语言——文件重定向

    千次阅读 2018-03-16 22:05:13
     由于变量在未赋值之前的值是不确定的(初值不一定为0),这时我们可以用文件把输入数据保存在文件中,输出数据也保存在文件中,而使用文件最简单的方法便是使用输入输出重定向,只需在main函数的入口处加入以下两...
  • 在进行MCU处理器的程序调试时,免不了需要使用串口打印调试信息到PC端进行程序代码运行状态的追踪监视,使用串口自身的发送函数进行输出打印,难免不是很灵活,一般情况下对printf函数进行重定向,打印调试信息。...
  • 不知道你们写单片机程序的时候有没有烦恼,它没有想c语言的dos窗口,没有java的运行窗口,没有python的控制台,有时候想输出一条调试信息却无法做到,下面通过简单的方法,将调试信息通过51单片机的串口输出到串口。...
  • 重定向函数的理解

    2022-05-14 02:01:47
    重定向函数的理解
  • 1.建立工程2.核心:添加新文件usar_fputc.c (名字随便自己命名),把文件添加到项目中去#include "stdio.h"#include "stm32f1xx_hal.h"extern ...//重写这个函数,重定向printf函数到串口/*fputc*/int fputc(int c, ...
  • 标准库函数的默认输出设备是显示器,要实现在串口或LCD上的输出,必须重定义标准库函数中与输出设备相关的函数. 如printf()之类的函数,使用了半主机模式。使用标准库会导致程序无法运行,解决方法如下: 方法1:...
  • /// 重定向c库函数printf到USART1 int fputc(int ch, FILE *f) { /* 发送一个字节数据到USART1 */ USART_SendData(USART1, (uint8_t) ch); /* 等待发送完毕 */ while (USART_GetFlagStatus(USART1, USART...
  • C语言数据流重定向

    千次阅读 2022-03-29 11:51:54
    数据流重定向 从前面章节中我们对标准输入输出和文件输入输出有了完整的概念,它们都操作数据流,只是输入输出的目标不同,这些函数都是同步函数,它们在底层调用系统io,执行完后再执行下面的代码。可以发现两者...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 104,731
精华内容 41,892
关键字:

c函数重定向