1

Mac で開発した ANSI C コードをいくつか持っていますが、それを学校の Linux サーバーで実行しようとすると、セグメンテーション違反が発生します。

問題を引き起こしている特定の行はgetc、ファイルポインターからのものです。

ファイルは存在します。

問題のメソッドは次のとおりです。

// inits lists with all data in fp file pointer
// returns # of lines read
int init_intlists(FILE *fp, INTLIST *lists[]) {
    int c, ctr;

    ctr = 0;

    // need to use a linked list to store current number
    // for non 1-digit numbers...
    INTLIST *cur_num = NULL;
    int cur_num_len = 0;
    while ((c = getc(fp)) != EOF){
        if(c != '\n' && c != ' '){
            c = c - 48;
            if(cur_num == NULL){
                cur_num = init_intlist(c);
            } else {
                list_append(cur_num, &c);
            }
            cur_num_len++;
        } else if(c == ' ' || c == '\n'){
            // we reached a space, meaning we finished
            // reading a contiguous block of digits
            // now we need to figure out what we actually read...
            int num = 0;
            INTLIST *ptr;
            ptr = cur_num;
            while(cur_num_len != 0){
                cur_num_len--;
                num += pow(10, cur_num_len) * ptr->datum;
                ptr = ptr->next;
            }    

            if(lists[ctr] == NULL){
                // init new list
                lists[ctr] = init_intlist(num);
            } else {
                // append to existing
                list_append(lists[ctr], &num);
            }

            // clear cur_num to read the next one
            cur_num_len = 0;
            list_delete(cur_num);
            cur_num = NULL;
        }

        if(c == '\n') {
            // newline reached - increment to fill in next list
            ctr++;
        }
    }    

    return ctr;
}

その呼び出しinit_intlistsにより、セグメンテーション違反が次のように開始されます。

    FILE *fp = (FILE *)malloc(sizeof(FILE));
    FILE *base_vector_fp = (FILE *)malloc(sizeof(FILE));

    parse_args(argc, argv, fp, base_vector_fp);

    if(fp == NULL || base_vector_fp == NULL){
        fprintf(stderr, "Critical error, could not load input files\n");
        return 1;
    }

    INTLIST *lines[MAX_LINES] = {};
    INTLIST *base_vectors[MAX_LINES] = {};

    int lines_read = init_intlists(fp, lines);

次のようになりparse_argsます。

FILE *load_file(char *filename) {
    FILE *fp;

    fp = fopen(filename, "r");

    if(fp == NULL){
        fprintf(stderr, "File %s does not seem to exist.\n", filename);
        return NULL;
    }

    // XXX Does this memory leak?
    // fp is never fclose()'d
    return fp;
}

void parse_args(int argc, char *argv[], FILE *fp, FILE *base_vector_fp) {
    char *prog = argv[0];
    if (argc != 3){
        fprintf(stderr, "Wrong number of arguments supplied.\nUse: %s <data_filename>     <base_vector_filename>\n", prog);
        free(fp);
        free(base_vector_fp);
        fp = NULL;
        base_vector_fp = NULL;
        exit(1);
    }

    char *filename = argv[1];
    *fp = *load_file(filename);

    char *base_vector_filename = argv[2];
    *base_vector_fp = *load_file(base_vector_filename);
}

そのため、Mac でこれを呼び出そうとすると、完全に正常に動作し、ファイルが正常に読み込まれ、それを操作して課題の正しい答えを得ることができます。

getcただし、Linux で実行しようとすると、init_intlistsサブルーチンで実行しようとすると segfault が発生します。

入力用に指定したファイルが存在し、誰でも読み取り可能であることを確認しました (umask 755)。絶対パスと相対パスの両方で試しました。いくつかの異なる入力ファイルも試しました。

gcc 4.2Linux サーバーでとを使用してみgcc 3.4ましたが、どちらも特定の入力ファイルでセグメンテーション違反を引き起こすバイナリ実行可能ファイルを生成します。

gcc の 2 つの異なるバージョン間のバージョン情報は次のとおりです。

Mac OS X:

me@dinosaurhunter ~> gcc -v
Using built-in specs.
Target: i686-apple-darwin9
Configured with: /var/tmp/gcc/gcc-5465~16/src/configure --disable-checking -enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.0/ --with-gxx-include-dir=/include/c++/4.0.0 --with-slibdir=/usr/lib --build=i686-apple-darwin9 --with-arch=apple --with-tune=generic --host=i686-apple-darwin9 --target=i686-apple-darwin9
Thread model: posix
gcc version 4.0.1 (Apple Inc. build 5465)

Linux:

me@janus:~/assignment_1$ gcc -v
Using built-in specs.
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.2 --program-suffix=-4.2 --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.2.4 (Ubuntu 4.2.4-1ubuntu4)

MakefileOS X と Linux の両方で同じものを使用してコンパイラを呼び出します。の最後の呼び出しは、次のgccようになります。

gcc  -Wall -g  -c src/common_file_io.c src/main.c src/intlist.c
gcc  -Wall -g  common_file_io.o main.o intlist.o -lreadline -lm  -o bin/myprogram 

何か案は?私の教授と同様に、私は完全に途方に暮れています。

4

3 に答える 3

10

独自のオブジェクトを割り当てることは想定されていませんFILE。通常、それらは libc によって管理される不透明なオブジェクトです。free()それらもしないでください。それは によって行われfclose(3)ます。理論的には、1 つを割り当てて構造体の割り当てを行い、それを機能させることができますが、ライブラリと競合せず、他のすべての人のように参照を渡すだけの方がよいでしょう。ライブラリは FILE 構造にない状態を保持する場合と保持しない場合があり、構造体全体の内部をのぞき見したり逆参照したりすることは十分に悪いスタイルであり、実装者は実際にはそうしないと想定する可能性があります。

を返したい場合FILE *は、あるケースで行ったようにリターン ポインター値として使用するか、二重間接ポインターを使用できますFILE *fp; f(&fp);

うーん、C99 が7.19.13で実際にこれを指定していることに気付きました:

6 ストリームを制御するために使用される FILE オブジェクトのアドレスは重要な場合があります。FILE オブジェクトのコピーは、オリジナルの代わりに提供する必要はありません。

FILE *これにより、aは単なる魔法のクッキーである可能性があるという通知が表示されます。

于 2009-10-27T22:27:00.127 に答える
2

他の答えは正しいです-FILE *あなたがコピーする不透明なハンドルとして扱い、その内容をコピーしようとしないでください。具体的には、次のようにコードを修正できます。

malloc初期化するときにへの呼び出しを削除しfpbase_vector_fp

FILE *fp = NULL;
FILE *base_vector_fp = NULL;

これらのポインタへのポインタをに渡してparse_args、ポインタ値を更新できるようにします。

parse_args(argc, argv, &fp, &base_vector_fp);

そして、オブジェクトを操作しようとするのではなく、呼び出し元parse_argsのオブジェクトを更新するように変更します。FILE *FILE

void parse_args(int argc, char *argv[], FILE **fp, FILE **base_vector_fp) {
    char *prog = argv[0];
    if (argc != 3){
        fprintf(stderr, "Wrong number of arguments supplied.\nUse: %s <data_filename>     <base_vector_filename>\n", prog);
        exit(1);
    }

    char *filename = argv[1];
    *fp = load_file(filename);

    char *base_vector_filename = argv[2];
    *base_vector_fp = load_file(base_vector_filename);
}
于 2009-10-27T23:07:39.377 に答える
0

の結果をオブジェクトにコピーするべきではありませfopen()ん。FILE実際、オブジェクトにmallocコピーするべきではありませんFILE。コントロール オブジェクトfopen()の割り当てには常に を使用する必要があります。FILE

このFILE物体は不透明で、ただの人間には隠されている多くのものを含んでいます。実装は、他の制御構造へのポインターなど、あらゆる種類のものを自由に配置できます。

于 2009-10-27T22:27:54.180 に答える