7

全て、

ストリームに出力するプログラムがあります。このストリームをメモリにバッファリングし、必要に応じて各行を後で実際のファイルに出力する必要があります。

fprintf()関数呼び出しにはFILE *ポインターが必要なので、メモリー内にポインターのアドレス空間を指定する必要があります。関数を使用していましたopen_memstream()が、これは Windows ではサポートされていません。

必要に応じて必要なポインターに魔法のようにキャストするポインターをmalloc()返すので、それをポインターとして使用できますか? その場合、どのような注意事項がありますか? 容量不足に注意する必要はありますか?void *FILE *

アップデート:

のソースを見つけた後open_memstream()、それは本来よりも困難でしたが、malloc されたスペースへのファイル ストリームを実行しているようです。

それが事実であり、私は彼らのソースを持っているので、mingw を使用して Windows 用にクロス コンパイルするための作業バージョンを取得できないかどうかを確認します。

4

2 に答える 2

8

私の後に来る人たちのために、希望を持ってください!解決策があります。私の質問で述べたように、私はopen_memstream()Windowsでサポートされていないを使用していました。

私はFile *ポインタを持っているので(これはに変更できませんchar *)、後でまでそれをメモリにリダイレクトする必要がありました。メモリ内のファイルを扱っているので、調べましたmmap()。それは手軽に問題を解決しますが、繰り返しになりますが、それはLinuxのみです。

ただし、windowsにはmmap()と呼ばれる結果が含まれていMapViewOfFile()ます。#ifdef私の魔法を通して、必要なものを使ってそれを手に入れました:

#ifdef WIN32
#include <windows.h>
#else
#include <sys/mman.h>
#endif

後で、mainメソッドで、tmpfile()両方のプラットフォームでサポートされているを呼び出します。これにより、保証された一意の一時ファイルへのストリームが開きます。FILE *ポインタができたので、スペースに移動する必要がありmmap()ます。ただしmmap()、ストリームではなくファイル記述子が必要なため、このfileno()関数を使用して新しいファイル記述子を取得しました。

/* create tmp file and get file descriptor */
int fd;
yyout = tmpfile();
fd = fileno(yyout);

#ifdefこれで、使用する必要のあるメモリマッピングコードセットを決定するためのコードがもう少しあります。2つのバージョン間のマップされたスペースの違いに注意してください。Windowsマップ16384 bytesとLinuxマップ4096 bytes。これは、ここでの私の質問で述べたように、小さい値のsegfaultsがWindowsで発生するためです。

#ifdef WIN32
    HANDLE fm;
    HANDLE h = (HANDLE) _get_osfhandle (fd);

    fm = CreateFileMapping(
             h,
             NULL,
             PAGE_READWRITE|SEC_RESERVE,
             0,
             16384,
             NULL);
    if (fm == NULL) { 
            fprintf (stderr, "%s: Couldn't access memory space! %s\n", argv[0],  strerror (GetLastError()));
            exit(GetLastError());
    }
    bp = (char*)MapViewOfFile(
              fm,
              FILE_MAP_ALL_ACCESS,
              0,
              0,
              0);
    if (bp == NULL) { 
            fprintf (stderr, "%s: Couldn't fill memory space! %s\n", argv[0],  strerror (GetLastError()));
            exit(GetLastError());
    }
#else
    bp = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_FILE|MAP_PRIVATE, fd, 0);
    if (bp == MAP_FAILED) {
            fprintf (stderr, "%s: Couldn't access memory space! %s\n", argv[0], FileName, strerror (errno));
            exit(errno);
    }
#endif

yyoutデータがストリームに送信されると、多くの作業が発生します。最終的に、flushData()メソッドが呼び出されます。ストリームをnullで終了する文字で終了し、フラッシュしてから巻き戻します。次に、メモリスペースへのポインタが、印刷先の適切なストリームとともに関数ポインタを通過します。

void flushData(void) {
    /* write out data in the stream and reset */ 
    while (currFields < headerFields) { fprintf(yyout, ",\"\""); currFields++; } 
    currFields = 0;
    fprintf(yyout, "%c%c%c", 13, 10, '\0');
    fflush(yyout);
    rewind(yyout);
    if (faqLine == 1) {
        faqLine = 0; /* don't print faq's to the data file */
    }
    else {
        (*printString)(outfile, bp);
        fflush(outfile);
    }
    fflush(yyout);
    rewind(yyout);
}

これは、印刷のために指すことができる機能の1つです。メモリスペースをウォークし、前に印刷されたnullに達するまで各文字を印刷します。

int printAnsi( FILE *outstream, char *string) {
    /* loop over the chars in string and print them to the outputstream as ansi */
    char * ps = string;
    while (*ps != '\0') {
        fprintf(outstream, "%c", *ps);
        ps++;
    }
    return 0;
}

これらすべての結果として、メモリスペースへのストリームがありopen_memstream()、必要に応じてメモリスペースをウォークスルーするために使用できるcharポインタもあります。それはクロスプラットフォームであり、(一見)完全に機能しています。

誰かが詳細を知りたい場合、または私が修正すべき問題についてのメモがある場合は、コメントを追加してください。

于 2012-04-26T20:37:49.810 に答える
2

いいえmalloc()。(おそらく初期化されていない)メモリのブロックを提供するだけです。「魔法の」キャストは行われていません。あなたがそうするとき、あなたは事実上、10個の初期化されていないintint * buf = malloc(10*sizeof(int);を指しています。buf

FILEに対応するのは、初期化されていない10個のFILE構造FILE * f = malloc(10*sizeof(FILE));を指すことですfが、これは意味がありません。さらに、初期化されていないFILEに書き込むと、運が良ければクラッシュする可能性があります。

対象としているプラ​​ットフォームと実際に達成したいことを教えていただければ、簡単にサポートできます。POSIXでは、shm_open()「共有メモリ」を指すファイル記述子を取得し、ファイル記述子fdopen()をに変換するために使用できますFILE*。はい、スペースが不足する可能性があります。

于 2012-04-24T20:04:16.680 に答える