debugging fopen()失败但似乎未返回NULL?

dl5txlt9  于 2022-11-14  发布在  其他
关注(0)|答案(1)|浏览(110)

下面的代码:

#include <stdio.h>
#include "config.h"
#include <errno.h>

char buffer[50];
long long bufSize = 50;
FILE* fptr;

char* readConfig(char* buffer, size_t bufSize) {
    fptr = fopen("config.txt", "rt");
    if (fptr == NULL) {
        return "error opening config file: %s", strerror(errno);
    } else {
        if ((fgets(buffer, bufSize, fptr)) == NULL) {
            fclose(fptr);
            return "error reading config file: %s", strerror(errno);
        }
        else {
            fclose(fptr);
            return buffer;
        }
    }
}

出于测试的目的,我删除了config.txt文件,这样fopen()函数应该返回NULL。会失败,但在两柴程式码时,它会略过“if(fptr == NULL){...}”部分,直接跳出函式。
继续调试过程时,我在尝试使用readConfig()的返回值“0xC 0000005”时收到以下错误:阅读位置0xFFFFFFFFA 4 E0 EB 70时发生访问冲突”

tvmytwxo

tvmytwxo1#

1.无法编译您的代码,因为您共享了一个代码段(没有main())并且未包含config.h。
1.将#include <string.h>转换为strerror()
1.建议调用方传入局部变量而不是全局变量。
1.使用sizeof来确定数组的大小,而不是在buffer[50]bufSize = 50;中硬编码大小。另一个好的替代方法是定义一个常量。

  1. fopen()模式“t”不是标准的,所以要么把它去掉,要么用windows或其他东西标记你的程序。
    1.当您返回错误时,请删除不必要的else &缩排。
    1.表达式return "error opening config file: %s", strerror(errno);没有按照你期望的方式工作,它将在void上下文中计算第一部分,然后返回第二部分strerror(errno)。否则我无法重现任何不良影响。
  2. fgets()在出现eof或错误时返回NULL,但不显示为设置errno。如果需要,可以使用feof()和/或ferror()来确定是哪一个。
    1.在调用fgets()之后,在检查errno之前调用fclose(),因此它具有fclose()调用的状态。
    1.返回错误消息或从文件中读取的值是不好的设计,因为您无法区分它们。更改为成功时返回NULL。
#include <errno.h>
#include <stdio.h>
#include <string.h>

char *readConfig(char *buffer, size_t bufSize) {
    FILE* fptr = fopen("config.txt", "r");
    if(!fptr)
        return strerror(errno);
    if(!fgets(buffer, bufSize, fptr)) {
        fclose(fptr);
        return "fgets eof/error";
    }
    fclose(fptr);
    return NULL;
}

int main(void) {
    char b[50];
    const char *error = readConfig(b, sizeof b);
    if(error) {
        printf("error: %s\n", error);
        return 1;
    }
    printf("%s", b);
}

考虑让调用者打开文件并传入FILE *。它为您提供了灵活性,例如,使用stdin作为文件句柄。
当需要清理资源时,我更喜欢使用goto,而不是多个返回。这里有点冗长,但每个错误情况的处理方式都是一样的。当你交换参数时,你可以记录它们与最新编译器的关系:

char *readConfig(size_t bufSize, char buffer[bufSize]) {
    char *r = NULL;
    FILE* fptr = fopen("config.txt", "r");
    if(!fptr) {
        r = strerror(errno);
        goto out;
    }
    if(!fgets(buffer, bufSize, fptr)) {
        r = "fgets eof/error";
        goto out;
    }
out:
    fptr && fclose(fptr);
    return r;
}

相关问题