【问题标题】:Float prints as NaN, but prints correct value immediately afterwardsFloat 打印为 NaN,但之后立即打印正确的值
【发布时间】:2016-12-20 17:05:17
【问题描述】:

根据我在代码中打印它们的位置,将浮点数打印为 NaN 时遇到了一些奇怪的问题。对于上下文,代码使用 BST 对地震数据列表进行排序,然后遍历排序的数据以找到两个连续地震之间的最大间隔。然后在此处打印这两次地震:

FILE* output_file = safe_open_file("task_1_bst.csv", "w");
fprintf(output_file, "timestamp,latitude,longitude,magnitude\n");
eq_print(output_file, sorted_arr[longest_index-1]);
fprintf(output_file, "\n");
eq_print(output_file, sorted_arr[longest_index-1]);
fprintf(output_file, "\n");
eq_print(output_file, sorted_arr[longest_index]);
fclose(output_file);

如您所见,我将其中一次地震打印了两次,结果如下:

timestamp,latitude,longitude,magnitude
2009-06-13T06:02:52.500Z,nan,-115.392,3.4
2009-06-13T06:02:52.500Z,31.315,-115.392,3.4
2009-06-13T16:04:06.650Z,3.930,126.648,4.4

由于某种原因,第一次打印时第一个 EQ 的纬度是 nan,但第二次打印正确。

代码太多了,这里就不一一列举了。 sorted_arr 数组中充满了指向 eq_t 类型的指针。

typedef struct {
    timestamp_t* timestamp;
    float latitude;
    float longitude;
    float magnitude;
    float x;
    float y;
} eq_t;

timestamp_t 只是一个整数结构(年、月、日、小时等),而 eq_print 只是一个 fprintf 的包装器,它打印 eq_t 和 timestamp_t 的每个字段。

void eq_print(FILE* fp, eq_t* q)
{
    fprintf(fp, "%d-%02d-%02dT%02d:%02d:%02d.%03dZ,%.3f,%.3f,%.1f",
        q->timestamp->year,
        q->timestamp->month,
        q->timestamp->day,
        q->timestamp->hour,
        q->timestamp->min,
        q->timestamp->sec,
        q->timestamp->msec,
        q->latitude,
        q->longitude,
        q->magnitude);
}

eq_print根本不修改eq_t,那么为什么两个fprintfs之间没有代码时打印出来的值不一样呢?

浮点数具有 NaN 值,然后立即具有正确值的原因是什么?

编辑:使用 GDB 逐行遍历这些行并在每行打印纬度会打印正确的值。

Breakpoint 1, task_1_find_longest_break_after_2k_bst (
    eq_csv_file=0x28cc87 "eq_data.csv") at tasks.c:128
128             FILE* output_file = safe_open_file("task_1_bst.csv", "w");
(gdb) warning: cYgFFFFFFFF 611B75D0 0
warning: cYgstd 0x28cbdf d 3
print sorted_arr[longest_index-1]->latitude
$1 = 31.3150005
(gdb) next
129             fprintf(output_file, "timestamp,latitude,longitude,magnitude\n");
(gdb) print sorted_arr[longest_index-1]->latitude
$2 = 31.3150005
(gdb) next
130             eq_print(output_file, sorted_arr[longest_index-1]);
(gdb) print sorted_arr[longest_index-1]->latitude
$3 = 31.3150005
(gdb) next
131             fprintf(output_file, "\n");
(gdb) print sorted_arr[longest_index-1]->latitude
$4 = 31.3150005
(gdb) next
132             eq_print(output_file, sorted_arr[longest_index-1]);
(gdb) print sorted_arr[longest_index-1]->latitude
$5 = 31.3150005

有一个警告,我不确定如何解释。

eq_t q 被这个函数赋值

eq_t* read_quake(FILE* fp)
{
    char buf[1024];
    float latitude, longitude, magnitude;
    if (fscanf(fp, "%[^,],%f,%f,%f\n", buf, &latitude, &longitude, &magnitude) == 4) {
        eq_t* eq = (eq_t*)safe_malloc(sizeof(eq_t));
        eq->timestamp = parse_time(buf);
        eq->latitude = latitude;
        eq->longitude = longitude;
        eq->magnitude = magnitude;
        map_coordinates(eq);
        return eq;
    }
    return NULL;
}

这里没有任何问题。好像是打印的问题。

【问题讨论】:

  • 根据您提供的信息无法判断。寻求调试帮助的问题(“为什么这段代码不起作用?”)必须包括所需的行为、特定的问题或错误以及在问题本身中重现它所需的最短代码。请参阅:How to create a Minimal, Complete, and Verifiable example
  • 基本上,q->会员怎么填很重要。
  • 可以在写入文件之前使用调试器检查数组中的值吗?这样,至少您将能够弄清楚问题是文件写入还是数据。程序也是多线程的吗?
  • @taskinoor 调试器在单步执行 fprintf 行时打印正确的值,但仍然打印不正确的数据。为帖子添加了 gdb 输出。

标签: c printing nan


【解决方案1】:

这是您的代码作为 MCVE (How to create a Minimal, Complete and Verifiable example) 的复制。

#include <math.h>       /* NAN */
#include <stdio.h>

/*
timestamp,latitude,longitude,magnitude
2009-06-13T06:02:52.500Z,nan,-115.392,3.4
2009-06-13T06:02:52.500Z,31.315,-115.392,3.4
2009-06-13T16:04:06.650Z,3.930,126.648,4.4
*/

typedef struct timestamp_t
{
    int year;
    int month;
    int day;
    int hour;
    int min;
    int sec;
    int msec;
} timestamp_t;

typedef struct
{
    timestamp_t* timestamp;
    float latitude;
    float longitude;
    float magnitude;  // x, y unused so removed
} eq_t;

static timestamp_t times[] =
{
    { 2009, 6, 13,  6,  2, 52, 500 },
    { 2009, 6, 13, 16,  4,  6, 650 },
};

static eq_t quakes[] =
{
    { &times[0],      NAN, -115.392F, 3.4F },
    { &times[1],  +3.930F, +126.648F, 4.4F },
};

static eq_t *sorted_arr[] = { &quakes[0], &quakes[1] };

static void eq_print(FILE* fp, eq_t* q)
{
    fprintf(fp, "%d-%02d-%02dT%02d:%02d:%02d.%03dZ,%.3f,%.3f,%.1f",
            q->timestamp->year,
            q->timestamp->month,
            q->timestamp->day,
            q->timestamp->hour,
            q->timestamp->min,
            q->timestamp->sec,
            q->timestamp->msec,
            q->latitude,
            q->longitude,
            q->magnitude);
}

int main(void)
{
    int longest_index = 1;
    FILE *output_file = stdout;
    fprintf(output_file, "timestamp,latitude,longitude,magnitude\n");
    eq_print(output_file, sorted_arr[longest_index-1]);
    fprintf(output_file, "\n");
    eq_print(output_file, sorted_arr[longest_index-1]);
    fprintf(output_file, "\n");
    eq_print(output_file, sorted_arr[longest_index]);
    fprintf(output_file, "\n");
    fclose(output_file);

    return 0;
}

我称它为nan11.c,它可以在 Mac OS X 10.11.6 上的 GCC 6.1.0 下干净地编译,并且运行两次并产生相同的输出:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
     -Wold-style-definition nan11.c -o nan11  
$ ./nan11
timestamp,latitude,longitude,magnitude
2009-06-13T06:02:52.500Z,nan,-115.392,3.4
2009-06-13T06:02:52.500Z,nan,-115.392,3.4
2009-06-13T16:04:06.650Z,3.930,126.648,4.4
$

当事情发生意外变化时,通常意味着内存管理存在问题,并且通常意味着在某处返回了局部变量。不过,这个错误在第二次打印操作中“自行修复”,这有点出乎意料。

您需要构建一个类似于我展示的实际执行读取、内存分配等的 MCVE,但仍然会遇到问题。您应该考虑在valgrind 下运行该代码,看看它是否可以发现内存滥用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-15
    • 2011-12-18
    • 1970-01-01
    • 2016-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多