1

私は C の初心者です。ungetc() を 2 回続けて呼び出したいのですが、通常の C では許可されていません。この仕事をするために変更できると誰かが私に言いましたがFflush()、私はそれを行う方法がわかりません。

これが私のコードです。私のFflush唯一の1つungetc()を許可します。2回許可したいです。

#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;
}     
4

2 に答える 2

5

コメントで賢明に述べたように、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 つ( の代わりに.残念ながら、これは、ストリームで, などを実行すると、悪い結果が生じることを意味します. !のすべてを書き直す必要があります.charfgetc()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;
}

xtdioxrewrap()バッファのサイズを拡張/縮小するなどのことを追加することで、さらに改善できます。

さらに良い解決策があります。コードをリファクタリングし、規則に従うことでungetc()、 2 回行う必要がなくなります。xtdio概念の証明にすぎませんが、適切なコードではなく、実際には使用しないでください。これにより、書き換えに対処する必要がなくなりstdioます。

于 2016-03-13T08:44:43.023 に答える