سؤال

ولدي بعض رمز ANSI C أنني وضعت على بلدي ماك، ولكن عندما حاولت تشغيله على خوادم لينكس مدرستنا أحصل على segfault.

وخط معين الذي يسبب لي مشكلة هو 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 الذي يسبب segfault تبدأ هكذا:

    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);
}

وهكذا عندما أحاول استدعاء هذا على بلدي ماك، وأنها تعمل على ما يرام تماما، ويقرأ الملف في كما ينبغي وأنا قادرة على العمل على ذلك والحصول على الإجابات الصحيحة لمهمتي.

ولكن عندما أحاول تشغيله على لينكس، وأحصل على segfault عندما كان يحاول getc في روتين init_intlists.

ولقد التحقق من أن الملفات I تزويد لإدخال موجودة ويمكن قراءتها في العالم (umask 755). لقد حاولت مع كل مسارات المطلقة والنسبية. لقد حاولت عدة ملفات الإدخال المختلفة كذلك.

ولقد حاولت استخدام gcc 4.2 وgcc 3.4 على خادم لينكس وكلاهما إنتاج قابل للتنفيذ ثنائي من شأنها أن تتسبب في segfault مع أي ملفات مدخلات معينة.

وهنا هي معلومات إصدار بين اثنين من إصدارات مختلفة من دول مجلس التعاون الخليجي:

وماك 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)

ولينكس:

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)

وأنا استدعاء مترجم باستخدام نفس Makefile على حد سواء OS 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 

وأي أفكار؟ أنا في حيرة كاملة، كما هو أستاذي.

هل كانت مفيدة؟

المحلول

والأجوبة أخرى صحيحة - علاج FILE * كما مقبض مبهمة الذي قمت بنسخ حولها، لا تحاول نسخ محتوياته. على وجه التحديد يمكنك إصلاح التعليمات البرمجية كما يلي:

وإزالة الدعوة إلى malloc عند التهيئة fp وbase_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);
}

نصائح أخرى

وأنت ليس من المفترض أن تخصص كائنات FILE الخاصة بك، فإنها عادة ما تكون الأجسام المعتمة التي تديرها LIBC. لا free() لهم سواء، وهذا ما قام به fclose(3). وعلى الرغم من الناحية النظرية يمكن تخصيص واحد والقيام تعيين هيكل ويكون ذلك العمل، سيكون من الأفضل عدم محاربة مكتبة ويمر حول مرجعية مثل أي شخص آخر لا. المكتبة قد أو قد لا تبقي على حالة غير موجود في بنية FILE، وتطل على داخل أو dereferencing البنية بكاملها هو نمط سيئة بما فيه الكفاية أن المنفذين قد تحمل في الواقع كنت لم تفعل ذلك.

إذا كنت ترغب في إرجاع FILE * يمكنك إما استخدامه بمثابة قيمة الإرجاع مؤشر كما فعلت في حالة واحدة أو استخدام مزدوج غير مباشرة المؤشر: FILE *fp; f(&fp);

وهم، أنا فقط لاحظت أن C99 يحدد هذا الواقع في على 7.19.13 : ل

<اقتباس فقرة>   

و6 عنوان الكائن FILE المستخدمة   للسيطرة على تيار قد يكون   كبير؛ نسخة من الكائن FILE   ليس من الضروري أن تكون في مكان   الأصلي.

ومع هذا أنهم يخدمون اشعار بأن FILE * قد حقا أن يكون مجرد الكعكة السحرية.

ويجب أن لا نسخ نتيجة offopen()into aFILEobject، وفي الواقع، يجب أن notmallocaFILEobject على الإطلاق. يجب عليك دائما usefopen()to تخصيص theFILEcontrol الكائن.

وTheFILEobject غير مبهمة، والحق أنه يحتوي على الكثير مما لا يخفى على البشر الفانين. تنفيذ حر في وضع جميع أنواع الأشياء فيه، مثل مؤشرات إلى هياكل المراقبة الأخرى، وما إلى ذلك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top