gpt4 book ai didi

c - 修改保证在 C 中连续调用 ungetc() 两次的 fflush()

转载 作者:太空宇宙 更新时间:2023-11-04 01:01:44 26 4
gpt4 key购买 nike

我是 C 初学者,我想连续调用 ungetc() 两次,尽管我知道在常规 C 中这是不允许的。有人告诉我可以修改 Fflush() 来完成这项工作,但我不知道该怎么做。

这是我的代码,我的Fflush只允许一个ungetc(),我希望它允许两次。

#define altUngetc(c, fp) ((fp)->next > (fp)->buffer && (c) != EOF ? \
*--(fp)->next = (c) : EOF)

int altGetc(ALT_FILE *fp) {
if (fp->next == fp->buffer + fp->bufSize)
altFflush(fp);

return fp->flags & FILE_ATEOF ? EOF : *fp->next++;
}

int altFflush(ALT_FILE *fp) {
int res;

if (fp->fd < 0 || fp->flags & FILE_ATEOF)
return EOF;
if (fp->flags & FILE_READ) {
res = read(fp->fd, fp->buffer, BUF_SIZE);
if (res == 0)
fp->flags |= FILE_ATEOF;
fp->bufSize = res;
fp->next = fp->buffer;
}
else {
res = write(fp->fd, fp->buffer, fp->next - fp->buffer);
fp->next = fp->buffer;
}
return res < 0 ? EOF : 0;
}

最佳答案

正如评论中明智地提到的那样,您可能应该首先学会遵守规则,而不是试图打破规则。但是,我们是来回答问题的,那就是打破规则!请注意,由于不同的原因,fflush()setbuf()setvbuf() 均无法在此处工作。

首先,至少需要四个自定义函数。一种是创建与文件相关的“代理缓冲区”(在 fopen() 之后调用),一种是销毁它(在 fclose() 之前调用),一种是做实际的 ungetting(ungetc() 的替换,以及从文件中检索 char 的一个(fgetc() 的替换)。不幸的是,这意味着在流上执行 fscanf()fflush() 等...将产生糟糕和丑陋的结果。您将不得不重写所有 标准输入输出!

首先,让我们调用我们所有的新东西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 库将允许您执行与传递给 xwrap() 的参数一样多的 ungets。每个 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() 两次。 xtdio 只是一个概念验证,但不是好的代码,切勿在实践中使用。这样,您就不必处理重写 stdio 的问题。

关于c - 修改保证在 C 中连续调用 ungetc() 两次的 fflush(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35967293/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com