【问题标题】:Error in reading uint32_t variable saved in a file读取保存在文件中的 uint32_t 变量时出错
【发布时间】:2017-04-14 23:44:35
【问题描述】:

我在将uint32_t 值写入文件并将其读回时遇到问题。 为了将其写入文件,我使用

uint32_t num = 2036465665 ; 
FILE *fp = fopen("test.dat", "w");
fprintf(fp,"value = %" PRIu32 "\n", num);
fclose(fp);

为了读取它,我首先将文件的内容复制到数组data[] 中,然后逐行提取值。

int len = 100;
char *line = malloc(len * sizeof(char));
char field[256], tmp[2];

FILE *fp = fopen("test.dat", "r");
while ( -1 != getline(&line, &len, fp)){
            char *value=malloc(sizeof(char)*256);
            sscanf( line, "%s %s %s", field, tmp, value);
            data[i] = value;
            i++;
        }
 fclose(fp);

为了读取 uint32_t 变量的值,我得到了 atoistrtoul 不同基数的不同值,但不是写入文件的确切值。

uint32_t read_num;
read_num = strtoul (data[0], NULL, 32);

这给出了 read_num 的值为 1345324165。

read_num = (uint32_t) atoi(data[0]);

提供 3226523632

如何获得保存在文件中的正确值。 (i) 使用 sscanf 将文件内容读取到字符串中或 (ii) strtoulatoi (iii) strtoul() 中的基数是否存在错误。

【问题讨论】:

  • strtoul (data[0], NULL, 32); -- 你的值是 32 进制的吗?我会查找如何正确使用此功能;根据我看过的应该是 10,而不是 32。
  • @MateoConLechuga:实际上,getline() 在 POSIX 中定义为返回-1 而不是EOF,所以使用-1 是正确的。
  • @kris:你打印出你读过的字符串了吗? data 数组的定义是什么?你检查sscanf()的返回值了吗?
  • 你的 test.dat 文件是 ascii 吗?如果可能,请发布它的样本。
  • 我的编译器抱怨 int len;getline() 期望的 size_t * 不匹配。这是你的问题的一个因素吗?修复后(我告诉编译器将警告视为错误),我让您的代码为我工作(macOS Sierra 10.12.4,GCC 6.3.0 — 64 位编译)。

标签: c uint32


【解决方案1】:

我将您的代码片段改编成这个接近 MCVE (Minimum, Complete, Verifiable Example),它似乎在我的运行 macOS Sierra 10.12.4 并使用 GCC 6.3.0 作为编译器的 Mac 上正常工作。 (我也得到了与 clang 相同的结果——Apple LLVM 版本 8.1.0 (clang-802.0.41)。)

#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>

static void write_data(const char *filename)
{
    uint32_t num = 2036465665; 
    FILE *fp = fopen(filename, "w");
    assert(fp != NULL);
    fprintf(fp,"value = %" PRIu32 "\n", num);
    printf("Wrote %" PRIu32 "\n", num);
    fclose(fp);
}

int main(void)
{
    const char filename[] = "test.dat";

    write_data(filename);

    char *data[10];
    size_t len = 100;
    char *line = malloc(len * sizeof(char));
    assert(line != 0);
    char field[256], tmp[2];

    FILE *fp = fopen(filename, "r");
    assert(fp != NULL);
    int i = 0;
    while ( -1 != getline(&line, &len, fp))
    {
        printf("Read: [%s]\n", line);
        char *value = malloc(sizeof(char)*256);
        assert(value != 0);
        if (sscanf(line, "%s %1s %s", field, tmp, value) != 3)
            assert(0);
        printf("Field [%s] tmp [%s] value [%s]\n", field, tmp, value);
        data[i] = value;
        i++;
    }
    free(line);
    fclose(fp);

    char *endptr;
    errno = 0;
    printf("Processing [%s]\n", data[0]);
    uint32_t read_num = strtoul(data[0], &endptr, 10);
    assert(endptr != data[0]);
    free(data[0]);

    printf("Number read: %" PRIu32 "\n", read_num);
    return 0;
}

使用assert 进行错误处理极其懒惰,但总比不检查好。 strtoul() 之后的错误检查也很草率——有未检查的条件(read_num == ULONG_MAXerrno == ERANGE 等)

编译并运行后,我得到:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
>     -Wstrict-prototypes -Wold-style-definition rd53.c -o rd53
$ ./rd53
Wrote 2036465665
Read: [value = 2036465665
]
Field [value] tmp [=] value [2036465665]
Processing [2036465665]
Number read: 2036465665
$

如果使用size_t len vs int len 不是你的问题,也许你可以试试这段代码,看看它能给你带来什么。

【讨论】:

  • 这对我来说也很好。太感谢了。但是,我还没有弄清楚为什么我的示例代码不起作用!
  • 在你的代码中使用 NULL 代替 endptr 是否与我有关?
  • 现在您需要将有效的部分整合到无效的部分。您正在使用版本控制系统,不是吗?
  • 否;使用 NULL 会丢失错误报告,但不会影响结果。添加打印;大量印刷。
  • 是的,将检查是否有外部因素可能影响我的代码。
猜你喜欢
  • 2014-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-06
  • 2016-03-28
  • 2015-06-17
  • 1970-01-01
  • 2019-03-26
相关资源
最近更新 更多