Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ajax/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C中存储不同类型的数据?_C_Polymorphism_Virtual Functions_C11 - Fatal编程技术网

如何在C中存储不同类型的数据?

如何在C中存储不同类型的数据?,c,polymorphism,virtual-functions,c11,C,Polymorphism,Virtual Functions,C11,我想存储一些数据,这些数据可以是只有在运行时才知道的不同类型的数据。我不想浪费任何内存,我想读取所有数据作为浮点值。在C++中我会做这样的事情< /P> struct IA { virtual float value(int index) = 0; }; template<class T> struct A : public IA { A(T* bytes, uint32_t size) { values.resize(size); memcpy(valu

我想存储一些数据,这些数据可以是只有在运行时才知道的不同类型的数据。我不想浪费任何内存,我想读取所有数据作为浮点值。在C++中我会做这样的事情< /P>
struct IA {
  virtual float value(int index) = 0;
};

template<class T>
struct A : public IA {
  A(T* bytes, uint32_t size) { 
    values.resize(size);
    memcpy(values.data(), bytes, size*sizeof(T));
  }
  float value(int index) override {
      return static_cast<float>(values[index]);
  }
  std::vector<T> values;
};


int main() {
  uint16_t bytes[] = {1, 2, 3, 4, 5 }; 
  IA *a = new A<uint16_t>(bytes, 5);
  float value = a->value(0);
  delete a;
}
struct IA{
虚拟浮点值(整数索引)=0;
};
模板
结构A:公共IA{
A(T*字节,uint32_T大小){
值。调整大小(大小);
memcpy(values.data(),字节,大小*sizeof(T));
}
浮点值(整型索引)覆盖{
返回静态_cast(值[索引]);
}
std::向量值;
};
int main(){
uint16_t字节[]={1,2,3,4,5};
IA*a=新的a(字节,5);
浮动值=a->值(0);
删除一条;
}
我的问题是如何用C++代替C++来完成这项工作。我可以将数据存储在
uint8\t
数组中,并存储位的nr和有符号的
值。然后,每次从数组中读取值时,都使用开关盒和强制转换。但是,如果阵列很大并且有很多读取,那么这将非常昂贵


我还希望能够传递数组,而无需执行任何特殊的if情况?

您可以使用函数指针模拟虚拟方法:

typedef struct
{
    void* userData;
    float (*value)(void*, int);
} IA;

float get_float_from_uint16(void* userData, int index)
{
    return ((uint16_t*) userData)[index];
}

int main()
{
    uint16_t bytes[] = {1, 2, 3, 4, 5 }; 
    IA a = {bytes, &get_float_from_uint16};

    int index = 0;
    float f = a.value(a.userData, index);
}

当然,这很简单(扰流板提示:不,不容易,很难)。我相信下面的代码和C++一样,但是用C语言编写。 那么会发生什么:

  • 首先,我定义了
    struct IA_s
    ,这是一个用于访问类似IA对象的接口。该结构仅包含用于访问对象的虚拟表。
    AI
    对象有一个访问器
    IA\u value
    ,它的作用与代码中的
    IA::value
    相同。我还将objects析构函数添加到虚拟表和作为析构函数的
    IA_fini
    函数中。您的代码中缺少它,并且代码会泄漏内存
  • 然后我创建了两个大宏
    A_C
    A_H
    A_H
    用于头文件中
    A_C
    用于源文件内部。它们为任何类型定义了
    对象的通用实现。第一个宏参数是用于为所有导出符号添加前缀的前缀。第二种是类型。
    A
    对象包含一些类型元素的动态数组
  • 然后我在
    uint16\u t
    type上用
    uint16\u
    前缀实例化泛型宏
  • 然后在main函数中,我为
    A
    对象分配内存,调用其构造函数,将其转换为
    IA
    对象,获取第二个索引的值并调用所有析构函数
注:

  • 构造函数被命名为
    *\u init
    ,析构函数被命名为
    *\u fini
    ,所有与对象接触的函数都被命名为
    object.*
  • 那很有趣
  • 我想我永远不会在生产中使用这样的代码
  • valgrind中释放的所有堆

#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
/*IA对象------------------------------------------*/
//IA表格的正向定义
结构单元;
//对象的虚拟表
结构表{
浮动(*值)(结构IA_s*ctx,大小索引);
无效(*fini)(结构IA_s*ctx);
};
//结构,仅容纳vtable
结构图{
const struct IA_uvtable_us*vtable;
};
/**
*获取索引中保留的值
*@param t
*@返回值
*/
浮动IA_值(结构IA_s*t、大小索引){
断言(t!=NULL);
断言(t->vtable!=NULL);
断言(t->vtable->value!=NULL);
返回t->vtable->value(t,索引);
}
/**
*调用IA对象的析构函数
*/
void IA_fini(结构IA_s*t){
断言(t!=NULL);
断言(t->vtable!=NULL);
断言(t->vtable->fini!=NULL);
t->vtable->fini(t);
}
/*对象-------------------------------------------*/
/**
*对象的头模板
*/
#定义一个_H(名称、类型)\
/*对象*/\
结构名称##A#s{\
\
/*指向已分配数组的指针*/\
类型*arr\
\
/*数组中的元素。*/\
尺寸\
\
/*我想我们必须这样做。*/\
结构IA_s IA\
\
}; \
\
/*初始化一个对象。*字节被复制到对象*/\
/*@param t*/\
/*@patam bytes指向对象大小计数的指针*/\
/*@param size*/\
/*@返回负errno错误值,0成功*/\
int NAME###A#init(结构名##A#s*t,TYPE*字节,size#t size)\
\
/*取消初始化对象。*/\
无效名称##A#fini(结构名称##A#s*t)\
\
/*转换IA对象中的对象*/\
结构IA#U s*名称#A#U to#U IA(结构名称#A#U s*t);
//末日
#定义一个_C(名称、类型)\
\
/*A到IA接口----------------------------------------------------*/\
\
/*将指向IA的指针转换为指向A的指针*/\
静止的\
结构名称##A#s*名称##A#pnt(来自#ia#u s*t{\
return(void*)((unsigned char*)(void*)t)-offsetof(struct NAME#A#u s,ia))\
} \
\
/*这是我们在IA接口内的值函数*/\
静止的\
浮点名称##A u IA_值(结构IA _s*IA,大小索引){\
结构名称##A#s*t=NAME##A#u pnt_from_ia(ia)\
断言(t!=NULL)\
/*UB发生,如vector::operator[]*/\
断言(索引cnt)\
返回t->arr[索引]\
} \
\
/*这是IA接口内的析构函数*/\
静止的\
无效名称35;#A#u IA_fini(struct IA#u s*IA){\
结构名称##A#s*t=NAME##A#u pnt_from_ia(ia)\
断言(t!=NULL)\
姓名##A#fini(t)\
} \
\
静态常量结构IA_uvtable_35;u vtable_35;A_uia_uvtable={\
.value=名称##A#u IA_值\
.fini=名称##A#u IA#u fini\
}; \
\
int NAME##A#init(结构名##A#s*t,TYPE*字节,size_t cnt){\
断言(t!=NULL)\
断言(字节!=NULL)\
如果(cnt==0){\
/*malloc(0)恰好是不可移植的*/\
t->arr=NULL\
t->cnt=0\
返回0\
} \
如果(SIZE_MAX/sizeof(*t->arr)#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* IA object ---------------------------------------------- */

// forward definition for IA__vtable_s
struct IA_s;

// the virtual table of the object
struct IA__vtable_s {
    float (*value)(struct IA_s *ctx, size_t index);
    void (*fini)(struct IA_s *ctx);
};

// The structure, holds only the vtable
struct IA_s {
    const struct IA__vtable_s *vtable;
};

/**
 * Get the value holded in index index
 * @param t
 * @return the value
 */
float IA_value(struct IA_s *t, size_t index) {
    assert(t != NULL);
    assert(t->vtable != NULL);
    assert(t->vtable->value != NULL);
    return t->vtable->value(t, index);
}

/**
 * Call the destructor of IA object
 */
void IA_fini(struct IA_s *t) {
    assert(t != NULL);
    assert(t->vtable != NULL);
    assert(t->vtable->fini != NULL);
    t->vtable->fini(t);
}

/* A object ---------------------------------------------- */

/**
 * Header template of A object
 */
#define A_H(NAME, TYPE)  \
/* A object */ \
struct NAME##A_s { \
\
   /* pointer to allocated array */ \
   TYPE *arr; \
\
   /* elements in the array. */ \
   size_t cnt; \
\
   /* I think we have to have that. */ \
   struct IA_s ia; \
\
}; \
\
/* Initializes A object. The *bytes are copied into the object */ \
/* @param t */ \
/* @patam bytes pointer to size count of objects */ \
/* @param size */ \
/* @returns negative errno value on error, 0 on success */ \
int NAME##A_init(struct NAME##A_s *t, TYPE *bytes, size_t size); \
\
/* Deinitializes A object. */ \
void NAME##A_fini(struct NAME##A_s *t); \
\
/* Converts A object in IA object */ \
struct IA_s *NAME##A_to_IA(struct NAME##A_s *t);
// end of A_H

#define A_C(NAME, TYPE) \
\
/* A to IA interface ----------------------------------------------------- */ \
\
/* Convert pointer to IA_s to pointer to A_s */ \
static \
struct NAME##A_s *NAME##A__pnt_from_ia(struct IA_s *t) { \
    return (void*)( ((unsigned char*)(void *)t) - offsetof(struct NAME##A_s, ia) ); \
} \
\
/* this is our value function inside IA interface */ \
static \
float NAME##A__IA_value(struct IA_s *ia, size_t index) { \
    struct NAME##A_s *t = NAME##A__pnt_from_ia(ia); \
    assert(t != NULL); \
    /* UB happens, as in case of vector::operator[] */ \
    assert(index <= t->cnt); \
    return t->arr[index]; \
} \
\
/* this is our destructor inside IA interface */ \
static \
void NAME##A__IA_fini(struct IA_s *ia) { \
    struct NAME##A_s *t = NAME##A__pnt_from_ia(ia); \
    assert(t != NULL); \
    NAME##A_fini(t); \
} \
\
static const struct IA__vtable_s NAME##A__IA_vtable = { \
    .value = NAME##A__IA_value, \
    .fini = NAME##A__IA_fini, \
}; \
\
int NAME##A_init(struct NAME##A_s *t, TYPE *bytes, size_t cnt) { \
    assert(t != NULL); \
    assert(bytes != NULL); \
    if (cnt == 0) {  \
       /* malloc(0) happens to be nonportable */ \
       t->arr = NULL; \
       t->cnt = 0; \
       return 0; \
    } \
    if (SIZE_MAX / sizeof(*t->arr) < cnt) { \
    /* multiplication overflow */ \
    return -EOVERFLOW; \
    } \
    t->arr = malloc(cnt * sizeof(*t->arr)); \
    if (t->arr == NULL) { \
        return -ENOMEM; \
    } \
    t->cnt = cnt; \
    memcpy(t->arr, bytes, cnt * sizeof(*t->arr)); \
    t->ia.vtable = &NAME##A__IA_vtable; \
    return 0; \
} \
void NAME##A_fini(struct NAME##A_s *t) { \
    assert(t != NULL); \
    free(t->arr); \
    t->arr = NULL; \
    t->cnt = 0; \
} \
struct IA_s *NAME##A_to_IA(struct NAME##A_s *t) { \
     assert(t != NULL); \
     return &t->ia; \
}

// A<uint16_t>
A_H(uint16_, uint16_t)
A_C(uint16_, uint16_t)

int main() {
    uint16_t bytes[] = {1, 2, 3, 4, 5 };

    // new()
    struct uint16_A_s *temp = malloc(sizeof(*temp));
    if (temp == NULL) {
        // destructors
        abort();
    }

    // A::A(bytes, 5)
    int ret = uint16_A_init(temp, bytes, 5);
    if (ret != 0) {
        // destructors
        free(temp);
        abort();
    }

    // IA *ia = A;
    struct IA_s *ia = uint16_A_to_IA(temp);
    if (ia == NULL) {
        // destructors
        uint16_A_fini(temp);
        free(temp);
        abort();
    }

    // finally call IA::value(2)
    float value = IA_value(ia, 2);
    printf("%f\n", value);

    // destructors
    IA_fini(ia); // or uint16_A_fini(temp) depending on which you call delete on

    free(temp);
}