我是一个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;
}

最佳答案

正如评论中明智地提到的,you should probably first learn to work with the rules instead of trying to break them。然而,我们是来回答这个问题的,这意味着违反规则考虑到fflush()setbuf()setvbuf()在这里都不起作用,原因各不相同。
首先,至少需要四个自定义函数一个用于创建与文件相关的“代理缓冲区”(在fopen()之后调用),一个用于销毁文件(在fclose()之前调用),一个用于执行实际取消设置(替换ungetc(),另一个用于从文件中检索char(替换fgetc())不幸的是,这意味着执行fscanf()fflush()等。。。顺流而下会给你带来糟糕和丑陋的结果。你必须重写所有的stdio
首先,让我们调用我们所有的新东西xtdio(“extendedstdio”),因此,首先是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()。示例用例。。。
#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;
}

fgetc()可以通过添加诸如xtdio之类的内容来扩展/缩小缓冲区的大小来进一步改进。
还有一个更好的解决方案,就是重构代码,并遵循约定,这样就不必两次xrewrap()ungetc()只是概念的证明,但不是好的代码,永远不能在实践中使用。这样,您就不必处理重写xtdio

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

10-12 06:47