纯ANSI-C:制作通用数组

时间:2010-12-12 17:52:36

标签: c arrays generics typeof dynamic-typing

是否可以在纯ANSI-C中复制通用数组?

我有这个结构,它包含一个数组(目前用于浮点数)和一些变量,如数组中的变异大小和容量。

typedef struct _CustomArray
{
    float* array; //the array in which the objects will be stored
    int size; //the current size of the array
    int capacity; //the max capacity of the array
} CustomArray; 

我使用这个结构,所以我可以在纯C中创建一个数组,在那里我可以添加/删除项目,在需要时动态扩展数组大小等所有“标准”数组所做的事情,除了它只在C中制作。 现在我想这样做,这样当你初始化这个结构时,你可以设置它应该保存的元素的数据类型,此时它只能存储浮点数据类型,但我想使它能够存储任何数据类型/其他结构。但我不知道这是否可能。

此时制作此数组的函数是:

CustomArray* CustomArray_Create(int initCapacity, /*type elementType*/)
{
    CustomArray* customArray_ptr; //create pointer to point at the structure
    float* internalArray = (float*)malloc(sizeof(float) * initCapacity); //create the internal array that holds the items
    if(internalArray != NULL)
    {
        CustomArray customArray = { internalArray, 0, initCapacity }; //make the struct with the data
        customArray_ptr = &customArray; //get the adress of the structure and assign it to the pointer
        return customArray_ptr; //return the pointer
    }
    return NULL;
}

是否可以将数据类型作为参数提供,以便我可以为该数据类型使用malloc内存并将其作为给定数据类型动态地转换为数组?

提前致谢,

Marnix van Rijswijk

5 个答案:

答案 0 :(得分:8)

您的代码存在严重问题...您正在返回局部变量(CustomArray)的地址,并且当函数返回时该变量被销毁,因此您无法继续将其与指针一起使用。你还必须使用malloc结构,以便在函数返回后内存仍然可用。

关于使类型成为参数,您可以使用宏稍微接近...例如:

#include <stdlib.h> 
#define DefArray(type) \
typedef struct T_##type##Array {\
    type *array; \
    int size, capacity; \
} type##Array; \
static type##Array *type##ArrayCreate(int capacity)\
{\
    type##Array *s = malloc(sizeof(type##Array));\
    if (!s) return NULL;\
    s->array = malloc(sizeof(type) * capacity);\
    if (!s->array) { free(s); return NULL; }\
    s->size=0; s->capacity = capacity;\
    return s;\
}

然后你可以这样使用它

#include "customarray.h"
DefArray(float);
DefArray(double);

void foo()
{
    floatArray *fa = floatArrayCreate(100);
    ...
}

请注意,您必须使用宏来定义所有自定义函数。另请注意,此方法将复制每个模块中的代码(我说不是一个大问题,但如果您不能使用C ++,则可能您的目标平台非常小)。使用稍微复杂的方法,您可以为实现生成单独的.h文件和.c文件。

答案 1 :(得分:2)

男孩,这听起来像是C ++的工作。

我认为你在C中最接近的是不通过类型,而是传递大小(sizeof(type))。

您可以使您的函数更通用,以便它可以执行它需要做的事情,如果它只知道数组中每个项目的大小。这就是像bsearch()这样的函数的工作方式。

答案 2 :(得分:2)

实现这一目标的一种方法是使用所谓的X-macros

Here是使用这种技术的(可能是错误的)通用矢量实现。

然后用作

// defining generic parameters
#define PREFIX tv
#define ITEM token
#define NAME token_vector
#include "vector.h"

...
token_vector tv = tv_new(100);
*(tv.front) = some_token;
tv_push_back(&tv, other_token);

答案 3 :(得分:0)

几年前,我在C语言中搞乱了泛型编程,只是为了它的存在。

基本上,我最终开发了预处理器。我想我有点成功:我确实为几个最重要的通用数据结构完成了一些宏表示法。

我绝对没有完成(至少以任何自动方式)是以递归方式运行宏 - 即创建数组数组或散列数组等。这是由于有趣的咳嗽疯狂咳嗽 C预处理器宏的语义。

如果您有兴趣,请输入以下代码:https://github.com/christianfriedl/CGenerics/blob/master/src/cgArray.h

答案 4 :(得分:0)

因此,对于没有自己声明类型的对象,有一个“有效类型”的概念。 (随着它的震动,它们几乎只由“ * alloc指针的另一端”和一些奇怪的联合规则组成) 基本上,此类对象的“有效类型”是您最后一次分配给它的对象,而不计算由于原因而为charchar[]的时间。

一个有趣的交互作用与声明结构类型的规则有关。也就是说,您可以自由地重新声明相同的标签名(或缺少标签名),并且每个声明都引入了一个全新的类型(过去的名称已被遮盖,但是具有旧类型的对象不会得到重新解释)。

因此您可以执行以下操作:

# define DECL_VECTOR(NAME,TYPE,SIZE) PUN_STRUCT(NAME,TYPE,SIZE)  INIT_STRUCT(NAME,TYPE,SIZE) 

# define PUN_SIZE sizeof(void*)+sizeof(int)*2


# define PUN_STRUCT(NAME,TYPE,SIZE)                      \
   struct {                                              \
      TYPE (*p)[(SIZE)];                                 \
      int size;                                          \
      int capacity;                                      \
   } *NAME = malloc(PUN_SIZE);                        


# define INIT_STRUCT(NAME,TYPE,SIZE)  do {               \
   if (!NAME) {                                          \
        perror("malloc fail");                           \
        abort();                                         \
   }else {                                               \
        NAME->size = (SIZE);                             \
        NAME->capacity = 0;                              \
        NAME->p = malloc(sizeof(*NAME->p));              \
        if (!NAME->p) {                                  \
            perror("malloc fail");                       \
            abort();                                     \
        }                                                \
        NAME->p = (TYPE(*)[(SIZE)])(NAME->p);            \
   }                                                     \
   }while(false)


int main(int argc, char *argv[]) 
 {

   DECL_VECTOR(vec1,int,8);


    printf("size of handle struct:  %zu,\n\
size of vector array:   %zu,\n\
size of vector element: %zu\n\
address of handle struct: %p,\n\
address of vector array:  %p\n",  sizeof(*vec1),       \
                                  sizeof(*vec1->p),    \
                                  sizeof(*vec1->p[0]), \
                                  vec1,                \
                                  vec1->p);
   free(vec1->p);
   free(vec1);
   return 0;
 }

(但是,人们可能会指责您滥用您的宏特权,而且他们可能并不完全错误)