fread() 正在读取错误的数据,即使之前的块已正确读取

问题描述 投票:0回答:1

背景:
我正在尝试从 .goo 文件(Elegoo Mars 4 的 SLA 打印机文件格式)解析图层信息。

3D 模型的每一层都编码在存储在

goo_layer_definition[nlayers]
中的新二进制文件块中。

问题:
我的解析函数适用于第一个块。

goo_layer_definition[0]
的所有字段均已完美读取并打印出来。 然而,当我尝试读取第二块时出现了段错误。 即我在读入
goo_layer_definition[1]
时遇到错误。

对于第二个块,正确读取了 pause_flagpause_position_z 值。 但是,读入 layer_position_z 的值完全错误,并且在文件二进制文件中的任何位置都找不到。

此错误读取发生在 fread() 函数上,其中错误的数据被读入缓冲区。

总结
我被困在第一个块如何能够正确读取所有字段,并且第二个块的一部分被正确读取,但相同的代码只是决定在第二个块中的同一点读取错误的数据。

当循环 i=1 时,问题出现在 fread_goo_layer_content() 中。 问题出现就行了

if(!fread_le(&dst->layer_position_z, sizeof(float), 1, fp) ) return 0;

有人对可能出现的问题有建议吗?

// main.c
...
FILE *p_fin = fopen(argv[1], "rb");
if(p_fin == NULL){
  (void)PRINT_ERR("Failed to open %s\n\n", argv[1]);
  return ENOENT;
}
...
goo_layer_content_t *goo_layer_contents;
if(!fread_goo_layer_content(&goo_layer_contents, &goo_header_info, p_fin)){
  (void)PRINT_ERR("Failed to read content info for %s\n\n", argv[1]);
  return EIO;
}
...

注意:fread_le() 只是 fread() 的包装,但转换为小端。

// goo.c
int fread_goo_layer_definition(goo_layer_definition_t *dst, FILE *fp){
  if(!fread_le(&dst->pause_flag               , sizeof(int16_t ), 1, fp) ) return 0;
  if(!fread_le(&dst->pause_position_z         , sizeof(float   ), 1, fp) ) return 0; 
  if(!fread_le(&dst->layer_position_z         , sizeof(float   ), 1, fp) ) return 0; 
  if(!fread_le(&dst->layer_exposure_time      , sizeof(float   ), 1, fp) ) return 0; 
  if(!fread_le(&dst->layer_off_time           , sizeof(float   ), 1, fp) ) return 0;
  ...
  return 1;
}

int  fread_goo_layer_content(goo_layer_content_t **dst, goo_header_info_t *header, FILE *fp){
  // Jump to layer content segment
  if(fseek(fp, header->offset_of_layer_content, SEEK_SET)) return 0;

  *dst = (goo_layer_content_t*)calloc(header->total_layers, sizeof(goo_layer_content_t));
  if(*dst == NULL) return 0;

  // Loop through all layers and read their layer info
  for(int i=0; i < header->total_layers; i++){
    // Reading layer definition
    if(!fread_goo_layer_definition(&dst[i]->definition, fp) ) return 0;

    // Reading image data
    ...
  }
  return 1;
}
//goo.h
#pragma packed
typedef struct goo_layer_definition_t {
  int16_t  pause_flag               ;  // 
  float    pause_position_z         ;  // 
  float    layer_position_z         ;  // 
  float    layer_exposure_time      ;  // 
  float    layer_off_time           ;  // 
  float    before_lift_time         ;  // 
  float    after_lift_time          ;  // 
  float    after_retract_time       ;  // 
  float    lift_distance            ;  // 
  float    lift_speed               ;  // 
  float    second_lift_distance     ;  // 
  float    second_lift_speed        ;  // 
  float    retract_distance         ;  // 
  float    retract_speed            ;  // 
  float    second_retract_distance  ;  // 
  float    second_retract_speed     ;  // 
  int16_t  light_pwm                ;  // 
  uint16_t delimiter                ;  // 
} goo_layer_definition_t;

#pragma packed
typedef struct goo_layer_content_t {
  goo_layer_definition_t definition ;  // Layer definitions
  int32_t   data_size               ;  // Indicate size of image_data
  uint8_t   data_start              ;  // Fix value: 0x55 
  image_data_chunk_t *image_data    ;  // See spec PDF
  uint16_t  delimiter               ;  // Fix value: 0x0D_0A
} goo_layer_content_t;  

调试尝试:
我查看了 GDB 和十六进制编辑器并单步执行了每个 fread()。存储在缓冲区中的值在读取第二个块之前都是正确的

fread_le(&dst->layer_position_z...)
.

我还尝试打印每次读取的 fgetpos() ,并且位置以每次读取的正确量递增,即 u16 为 2 个字节,float 为 4 个字节。

我还将 fgetpos() 位置值与十六进制编辑器的地址偏移量进行了比较,并将其数据排列起来,直到读取第二个块上的 layer_position_x 为止。

我在十六进制编辑器中看到的内容:

correct datas ... 0A 8C 8D 1E 0D 0A 00 00 3C A3 D7 0A *3C A3 D7 0A*

我从 fread() 得到什么:

correct datas ... 0A 8C 8D 1E 0D 0A 00 00 3C A3 D7 0A *40 A3 D7 0D*

前面的204168字节都是正确的。 错误发生在地址 204172 上——我不确定这是否是对 fread() 的限制。 错误是一致的,每次运行都会在同一点读取相同的错误值。

我还检查了 GDB 中的 calloc() 值是否正确。我的 1 层测试文件为 1,2 层测试文件为 2。

预计:
我期望 fread() 将 3C A3 D7 0A 读入缓冲区,而不是 40 A3 D7 0D。

c memory-management file-io segmentation-fault fread
1个回答
0
投票

&dst[i]->definition
中的
fread_goo_layer_definition
应该是
&(*dst)[i].definition

首先是

(*dst)
,就像函数中的所有其他用途一样,然后是索引。

© www.soinside.com 2019 - 2024. All rights reserved.