首页 > 解决方案 > ftell 返回不准确的值

问题描述

所以,我在 c 中有这段代码,它应该从一个 ascii 文件中读取,然后返回一个被解析并编译成字节码的字符串。当我尝试使用 ftell 获取文件的大小时,它返回 33 而不是 29(文件包含新行的字节数)。

文件:

push #25
nop
push #44
add
hlt

编码:

uint8_t* read_ascii_file(uint8_t* path) {
    FILE* file = fopen(path, "r");
    if (file == NULL)
        return NULL;
    fseek(file, 0, SEEK_END);
    uint32_t size = ftell(file);
    fseek(file, 0, SEEK_SET);
    uint8_t* buffer = (uint8_t*)malloc(sizeof(uint8_t) * size);
    if (buffer == NULL)
        return NULL;
    fread(buffer, sizeof(uint8_t), size, file);
    buffer[size] = '\0';
    fclose(file);
    return buffer;
}

似乎无缘无故地又添加了四个字节。我的解析器抱怨“hlt====”不是一个有效的指令(“====”是 4 个额外的字节)。

Ftell 或 fseek 在这种情况下搞砸了,我不知道这是否是错误

我在 Windows 上,我也在使用 Visual Studio

标签: cftell

解决方案


你没有分配足够的空间。

您为文件内容分配sizeof(uint8_t) * size字节,但这不足以保存您稍后添加以终止字符串的空字节。所以你写超出了分配内存的范围,触发了未定义的行为

加 1 为空终止符留出空间。

uint8_t* buffer = (uint8_t*)malloc(sizeof(uint8_t) * size + 1);

此外,这些行是有问题的:

fread(buffer, sizeof(uint8_t), size, file);
buffer[size] = '\0';

由于 Windows 上换行符的翻译,最终读取的字节数会少于文件实际包含的字节数。这意味着终止的空字节位于错误的位置。

保存它的返回值fread将告诉您实际读取了多少字节,然后使用该值写入空字节。

size_t rval = fread(buffer, sizeof(uint8_t), size, file);
if (rval > 0) {
    buffer[rval] = '\0';
}

推荐阅读