コメントで賢明に述べたように、you should probably first learn to work with the rules instead of trying to break them
. しかし、私たちはその質問に答えるためにここにいます。それは、ルールを破ることを意味します! fflush()
、setbuf()
、または のいずれも、setvbuf()
さまざまな理由でここでは機能しないことを考慮してください。
まず、少なくとも 4 つのカスタム関数が必要です。ファイルに関連する「プロキシ バッファ」を作成する 1 つ ( の直後に呼び出されるfopen()
)、ファイルを破棄する 1 つ ( の直前に呼び出される ) fclose()
、実際の取得を解除する 1 つ ( の代わりに、ファイルからungetc()
を取得する 1 つ( の代わりに.残念ながら、これは、ストリームで, などを実行すると、悪い結果が生じることを意味します. !のすべてを書き直す必要があります.char
fgetc()
fscanf()
fflush()
stdio
まず、すべての新しいものを呼び出しましょう( xtdio
「拡張stdio
」) 。xtdio.h
#ifndef __XTDIO_H__
#define __XTDIO_H__
#include <stdio.h>
typedef struct
{
FILE *file;
char *buffer;
size_t buffer_size;
size_t buffer_usage;
size_t buffer_tail_offset;
} XFILE;
/* I know this is not the best of API design, but I need to be
* compatible with stdio's API.
*/
XFILE *xwrap(FILE *file, size_t max_ungets);
void xunwrap(XFILE *xfile);
int xgetc(XFILE *xfile);
int xungetc(int ch, XFILE *xfile);
#endif
次に、フェンスの興味深い側に来xtdio.c
ます...
#include <stdlib.h>
#include <stdio.h>
#include "xtdio.h"
/* Create a XFILE wrapper, along with its respective buffer
* of 'max_ungets' size, around 'file'.
*/
XFILE *xwrap(FILE *file, size_t max_ungets)
{
XFILE *xfile = malloc(sizeof(XFILE));
if(xfile == NULL)
return NULL;
xfile->file = file;
xfile->buffer = malloc(max_ungets);
if(xfile->buffer == NULL) {
free(xfile);
return NULL;
}
xfile->buffer_size = max_ungets;
xfile->buffer_usage = 0;
xfile->buffer_tail_offset = 0;
return xfile;
}
/* Undo what 'xwrap()' did.
*/
void xunwrap(XFILE *xfile)
{
free(xfile->buffer);
free(xfile);
}
/* Check if there's something in the XFILE's
* buffer, and return it. Otherwise, fallback
* onto 'fgetc()'.
*/
int xgetc(XFILE *xfile)
{
if(xfile->buffer_usage == 0)
return fgetc(xfile->file);
if(xfile->buffer_tail_offset == 0)
xfile->buffer_tail_offset = xfile->buffer_size - 1;
else
xfile->buffer_tail_offset--;
xfile->buffer_usage--;
return xfile->buffer[xfile->buffer_tail_offset];
}
/* Here's the interesting part! If there's room in the
* buffer, it puts 'ch' in its front. Otherwise, returns
* an error.
*/
int xungetc(int ch, XFILE *xfile)
{
if(xfile->buffer_usage == xfile->buffer_size)
return EOF; //TODO: Set errno or something
xfile->buffer[xfile->buffer_tail_offset++] = (char)ch;
xfile->buffer_tail_offset %= xfile->buffer_size;
xfile->buffer_usage++;
return ch;
}
小さめのxtdio
ライブラリを使用すると、 のパラメータに渡した数だけ ungets を実行できxwrap()
ます。それぞれXFILE
に、取得されていない文字を含むバッファーがあります。するとxgetc()
、最初にバッファに何かがあるかどうかを確認し、それを取得します。それ以外の場合は、にフォールバックしfgetc()
ます。使用例...
#include <stdio.h>
#include <string.h>
#include "xtdio.h"
int main()
{
const char *my_string = "I just ungot this same long string in standard and compliant C! No more one-char limits on ungetc()!\n";
const size_t my_string_len = strlen(my_string);
XFILE *xtdin = xwrap(stdin, my_string_len);
if(xtdin == NULL) {
perror("xwrap");
return 1;
}
for(size_t i = my_string_len; i != 0; i--)
xungetc(my_string[i - 1], xtdin);
int ch;
while((ch = xgetc(xtdin)) != EOF)
putchar(ch);
xunwrap(xtdin);
return 0;
}
xtdio
xrewrap()
バッファのサイズを拡張/縮小するなどのことを追加することで、さらに改善できます。
さらに良い解決策があります。コードをリファクタリングし、規則に従うことでungetc()
、 2 回行う必要がなくなります。xtdio
概念の証明にすぎませんが、適切なコードではなく、実際には使用しないでください。これにより、書き換えに対処する必要がなくなりstdio
ます。