GCC 优化:fgets 引起的错误

GCC Optimization: Error caused by fgets

我在我的 Mac 上编译代码并启用 GCC 优化标志 -O3 以加快执行时间。这在我的本地机器上完美运行,并导致速度提高 2/3。

但是,我尝试在 Amazon EC2 上编译代码,因为我正在处理一个大型数据集。使用 -O3 优化标志会导致以下警告

warning: call to ‘__fgets_chk_warn’ declared with attribute warning: fgets called with bigger size than length of destination buffer

在各自的函数中,逐行解析一个文本文件。但是,我真的不明白为什么我最终会收到警告。函数代码如下:

int loadPriceData(const char *filename, double *target) {
    char line[40];
    FILE *fp;
    fp = fopen(filename, "r");
    if (fp == NULL) {
        return -1;
    }
    int i = 0;
    while (fgets(line, 80, fp) != NULL) {
        sscanf(line, "%lf\n", target + i);
        i += 1;
    }
    fclose(fp);
    return i; // Return number of elements
}
默认情况下,

target 是指向具有 10000 个元素的数组的指针。条目数事先不知道,但由函数返回。

您确实在调用 fgets(line, 80, fp),但目标数组 line 被定义为 40 字符数组。 Amazon EC2 上的编译器比您的配置更好或更智能。如果文件包含超过 39 字节的行,这就是一个真正的错误。

顺便说一下,在 Mac 上作为 gcc 调用的编译器通常是 clang 的一个实例。试试 gcc --version.

请注意,您的程序不会检查是否读取了太多数据,也不会检查 sscanf() 转换是否成功。两者都会导致未定义的行为。

这是一个更安全的版本:

int loadPriceData(const char *filename, double *target, int nb_items) {
    char line[80];
    FILE *fp = fopen(filename, "r");
    if (fp == NULL) {
        return -1;
    }
    int i = 0;
    while (fgets(line, sizeof line, fp) != NULL) {
        if (i < nb_items) {
            if (sscanf(line, "%lf", target + i) != 1)
                target[i] = 0;
        }
        i += 1;
    }
    fclose(fp);
    return i; // Return number of elements
}