2.12.1. 对低级函数的依赖性

Table 2.13 显示了高级函数对低级函数的依赖性。 如果您定义了自己的低级函数版本,则可以直接使用库中的高级函数版本。fgetc() 使用 __FILE,但 fputc() 使用 __FILEferror()

Table 2.13. 输入/输出依赖性 

低级对象         高级函数        
  fprintf printf fwrite fputs puts fscanf scanf fread read fgets gets
__FILE [1] x x x x x x x x x x x
__stdin [2] - - - - - - x - x - x
__stdout [3] - x - - x - - - - - -
fputc() [4] x x x x x - - - - - -
ferror() [5] x x x - - - - - - - -
fgetc() [6] - - - - - x x x x x x
__backspace() [7] - - - - - x x - - - -

[1] 文件结构。

[2] __FILE 类型的标准输入对象。

[3] __FILE 类型的标准输出对象。

[4] 将一个字符输出到文件中。

[5] 返回在文件 I/O 期间累积的错误状态。

[6] 从文件中获取一个字符。

[7] 将文件指针移动到前一个字符。 请参阅重新实现 __backspace()

有关低级函数的语法,请参阅 ISO C 参考。

Note

如果选择重新实现 fgetc()fputc()__backspace(),请注意 fopen() 和相关函数使用 ARM 的 __FILE 结构布局。 如果您定义了自己的 __FILE 版本,可能还需要重新实现 fopen() 和相关函数。

printf 系列

printf 系列包含 _printf()printf()_fprintf()fprintf()vprintf()vfprintf()。 所有这些函数不透明地使用 __FILE,并且仅依赖于 fputc()ferror() 函数。 除了不能设置浮点值的格式外,printf()fprintf() 函数与 printf()fprintf() 是相同的。

_printf(...) 格式的标准输出函数等效于:


fprintf(& __stdout, ...) 

其中,__stdout 具有 __FILE 类型。

scanf 系列

scanf() 系列包含 scanf()fscanf()。 这些函数仅依赖于 fgetc()__FILE__backspace() 函数。 请参阅重新实现 __backspace()

scanf(...) 格式的标准输入函数等效于:


fscanf(& __stdin, ...)

其中,__stdin 具有 __FILE 类型。

fwrite()、fputs 和 puts

如果您定义了自己的 __FILE 版本、自己的 fputc()ferror() 函数以及 __stdout 对象,则可以直接使用库中的所有 printf() 系列、fwrite()fputs()puts() 以及 C++ 对象 std::cout,而无需进行更改。Example 2.24 说明了如何实现此操作。 如果需要实际进行文件处理,应考虑修改系统例程。

Example 2.24. printf() 和 __FILE


#include <stdio.h>	

struct __FILE

{	

    int handle;	

    /* Whatever you need here (if the only file you are using

       is the stdoutput using printf for debugging, no file

       handling is required) */	

};



FILE __stdout;	

int fputc(int ch, FILE *f)	

{

    /* Your implementation of fputc */	

    return ch;	

}

int ferror(FILE *f)	

{   

    /* Your implementation of ferror */	

    return EOF;	

}

void test(void)	

{

    printf("Hello world\n");  /* This works ... */	

}

缺省情况下,fread()fwrite() 调用快速块输入/输出函数,这些函数是 ARM 流实现的一部分。 如果您定义自己的 __FILE 结构而不是使用 ARM 流实现,fread()fwrite() 将调用 fgetc(),而不是调用块输入/输出函数。 另请参阅主示例目录的 ...\emb_sw_dev\source\retarget.c 中的实现。

fread()、fgets() 和 gets()

fread()fgets()gets() 函数是作为 fgetc()ferror() 中的循环实现的。 每个函数都不透明地使用 FILE 自变量。

如果您提供自己的 __FILE__stdin(用于 gets())、fgetc()ferror() 实现,则可以直接使用库中的这些函数以及 C++ 对象 std::cin

重新实现 __backspace()

__backspace() 函数由 scanf 函数系列使用。 切勿直接调用此函数,但如果在 fgetc() 级别重定向 stdio 布局的目标,则可以重新实现该函数。

语义为:

          int 
          __backspace(FILE *stream);
        

必须先从流中读出字符,然后再调用 __backspace(stream)。 它向流中返回从流中读取的最后一个字符,以便再次从流中读取同一字符。 这意味着,scanf 从流中读取一个字符,但它不是所需的字符(即,它终止 scanf 操作),下一个从流中读取数据的函数将正确读取该字符。

__backspaceungetc() 是分开的。 这可确保在 scanf 函数系列结束后推回单个字符。

__backspace() 返回的值是 0(成功)或 EOF(失败)。 它仅在使用不当时才返回 EOF,例如,没有从流中读取任何字符。 在正确使用时,__backspace() 一定会始终返回 0,因为 scanf 函数系列并不检查错误的返回结果。

__backspace()ungetc() 之间的交互是:

  • 如果对流应用 __backspace(),然后使用 ungetc() 将一个字符返回到相同的流中,则随后的 fgetc() 调用必须先返回由 ungetc() 返回的字符,然后返回由 __backspace() 返回的字符。

  • 如果使用 ungetc() 将一个字符返回到流中,随后使用 fgetc() 读取该字符,然后对此字符应用 backspace,则 fgetc() 读取的下一个字符一定是返回到流中的同一字符。 即,__backspace() 操作必须抵消 fgetc() 操作的效果。 不过,在调用 __backspace() 之后,不必再调用 ungetc() 即可成功完成操作。

  • 以下情况是从不会发生的:使用 ungetc() 将一个字符返回到流中,然后立即将 __backspace() 应用于另一个字符,而中间没有进行任何读取操作。必须先调用 fgetc(),然后才能调用 __backspace(),因此,上述调用顺序是非法的。 您可以编写 __backspace() 实现,并且假定不会发生这种情况。

Copyright © 2007 ARM Limited. All rights reserved. ARM DUI 0349AC
Non-Confidential