Передача void * ссылки для хранения произвольной структуры в функции - PullRequest
0 голосов
/ 08 апреля 2020

У меня есть программа cli, которая используется для связи с регистрами FPGA и памятью. В зависимости от команды, вы можете вернуть 32-битные регистры (которые могут состоять из нескольких полей), или он может быть размером до 128 байт. Итак, что я хотел сделать, так это сделать малые c 128 байт в глобальном масштабе для хранения возвращаемой структуры или для подготовки структуры для записи в ПЛИС. (см. void * entry_top.

. В приведенном ниже примере у меня есть единственная команда Get, которая завершается неудачно с ошибкой сегментации при попытке вывести значение полученного поля. В GDB я вижу, что адрес Кажется, что entry_top фактически не передается по ссылке в функцию io_get_entry, которая была намерением.

Я попытался упростить ситуацию, просто назначив тестовое значение 0x12345678 для записи, используя приведение (host_global_size_entry_t) *). В этой тестовой программе, на основном уровне, я полагал, что должен был бы привести void * к (host_global_size_entry_t *) и правильно прочитать установленное значение в entry_top.

Не уверен на 100%, но проблема, похоже, в том, что моя ссылка на память передается неправильно с использованием & entry_top.

Может кто-нибудь прокомментировать, что я сделал неправильно в отношении передачи ссылки void * entry_top на несколько уровней функций?

using namespace std;

#include "stdint.h"
#include <stdlib.h>
#include <list>
#include <string.h>
#include <string>
#include <iostream>


#ifndef __KRISTEN_TYPES_H__
#define __KRISTEN_TYPES_H__
#include <stdint.h>

#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
#ifdef PACKED
#undef PACKED
#endif /* PACKED */
#define PACKED __attribute__ ((packed))
#ifdef ALIGNED
#undef ALIGNED
#endif /* ALIGNED */
#define ALIGNED __attribute__ ((aligned (4)))
#ifdef __cplusplus
}
#endif /* __cplusplus */


typedef enum _return_t  
{                
    /* Common codes */  
    func_ok = 0,        
    func_failed,        
    func_invalid,       
    func_not_done       
} return_t;              

#endif // __KRISTEN_TYPES_H__


 uint32_t host_global_size_offset[1] = {53300};


 void *entry_top = malloc(32*sizeof(uint32_t));
 uint32_t *field_size = (uint32_t*)malloc(sizeof(uint32_t));
 uint32_t* result=(uint32_t*)malloc(64*sizeof(uint32_t));

struct _host_global_size_entry_t {
   union {
      struct {
         uint32_t global_size_field        : 32 ; // A generic bit field for this register.
      } PACKED; 
      uint8_t entry[5];
   } PACKED;
   uint8_t alignment_correction[3];
} PACKED;
typedef struct _host_global_size_entry_t __attribute__ ((aligned (4))) host_global_size_entry_t;


return_t io_get_entry(uint32_t index, void *entry, uint32_t base, uint8_t  length) {
   uint32_t local_addr = base + (index * length);
   ((host_global_size_entry_t*) entry)->global_size_field = 0x12345678;  // Assign a value that we can see in Main'
   // The next line shows that the value was 0x12345678 succesfully
   printf("io_get_entry local_addr = %d, length = %d, entry->global_sizefield = 0x%X\n", local_addr, length, ((host_global_size_entry_t*) entry)->global_size_field);
   return func_ok;
}


return_t host_global_size_read_entry(uint32_t index, void *entry, uint8_t instance) {
   return_t result;
   uint32_t base;
   uint8_t  length;
   base = host_global_size_offset[instance];
   length = sizeof(host_global_size_entry_t);
   result = io_get_entry(index, &entry, base, length);
   // The next printf causes a segmentation fault.  GDB says that &entry here is not the same as &entry in io_get_entry 
   printf("host_global_size_read_entry = 0x%X\n", ((host_global_size_entry_t*)entry)->global_size_field);

   return result;
}

return_t host_global_size_read_field(char *field, uint32_t *field_size, void *result, void *entry) {
//host_global_size_entry_t *entry;
   uint32_t field_s = 0;
   if (strcmp("global_size_field", field) == 0) {
      field_s = 4;
      *(uint32_t *)result = ((host_global_size_entry_t*)entry)->global_size_field; 
   } else   if (field_size != NULL) *field_size = field_s;
      *field_size = field_s;
   return func_ok;
}



int main (void) {
  uint8_t instance = 0;
  uint32_t index = 0;
  // Pass the address of entry_top global
  host_global_size_read_entry(index, &entry_top, instance); // Read entry.
  // Cast the result to the structure we expect to be comming back.  
  printf("main: entry_top->global_sizefield = 0x%X\n", ((host_global_size_entry_t*) entry_top)->global_size_field);
  return 0;
}

1 Ответ

1 голос
/ 08 апреля 2020

И в main, и в host_global_size_read_entry вы берете адрес из entry_top (соответственно entry). Это void **, но C ++ автоматически преобразует его в * 1008. * без жалоб.

Вместо этого вы должны передать entry_top по значению, чтобы host_global_size_read_entry и io_get_entry получили содержимое entry_top, ie указателя на выделенную память.

...