编辑:哦,天哪,我觉得自己很傻.当然,你不能从多头投掷到双打,而回头投球有更重要的部分.投出长双打会改善这一点吗?

我正在用C实现一个数组列表,我希望它是类型不可知的.我也不希望它在用法上如此冗长,因此我希望我的GET函数不返回空指针,并且需要用户进行类型转换.因此,我为该类型存储一个枚举(每个列表一个类型),它可以是int、Float、Long或Double.参数作为Double传递(因此,如果您传递int、Float或Long,编译器将隐式强制转换),然后根据列表中存储的数据类型,传递的Double将被强制转换为正确的类型.这会一直奏效吗?一个数字,转换为双精度型,然后返回到其原始类型,会有不同的值吗?这个最重要的 idea 还有其他问题吗?基本实现如下

#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>

typedef enum{
    INT,
    LONG,
    FLOAT,
    DOUBLE
}TYPE;

typedef struct arrayList{
    void * data;
    TYPE type;
    size_t capacity;
    size_t num_elements;
}arrayList;

void reallocateArrayList(arrayList * list, size_t capacity){
    TYPE type=list->type;
    if(type == INT){
        void * toAllocate = malloc(capacity*sizeof(int));
        memcpy(toAllocate, list->data, list->num_elements*sizeof(int));
        if(list->data!=NULL){
            free(list->data);
        }
        list->data = toAllocate;
    }
    if(type == FLOAT){
        void * toAllocate = malloc(capacity*sizeof(float));
        memcpy(toAllocate, list->data, list->num_elements*sizeof(float));
        if(list->data!=NULL){
            free(list->data);
        }
        list->data = toAllocate;
    }
    if(type==LONG){
        void * toAllocate = malloc(capacity*sizeof(long));
        memcpy(toAllocate, list->data, list->num_elements*sizeof(long));
        if(list->data!=NULL){
            free(list->data);
        }
        list->data = toAllocate;
    }
    if(type==DOUBLE){
        void * toAllocate = malloc(capacity*sizeof(double));
        memcpy(toAllocate, list->data, list->num_elements*sizeof(double));
        if(list->data!=NULL){
            free(list->data);
        }
        list->data = toAllocate;        
    }
    list->capacity=capacity;
    if(list->data==NULL) raise(ENOMEM);
}

arrayList * createArrayList(TYPE type){
    arrayList * retval = (arrayList *) malloc(sizeof(arrayList));
    retval->capacity=256;
    retval->data = NULL;
    retval->type = type;
    retval->num_elements = 0;
    reallocateArrayList(retval, 256);
    return retval;

}

void add(arrayList * list, double val){
    if(list->capacity<=list->num_elements){
        reallocateArrayList(list, 4*list->capacity);
    }
    TYPE type=list->type;
    if(type == INT){
        ((int *)(list->data))[list->num_elements]=(int) val;
    }
    if(type == FLOAT){
        ((float *)(list->data))[list->num_elements]=(float) val;
    }
    if(type==LONG){
        ((long *)(list->data))[list->num_elements]=(long) val;

    }
    if(type==DOUBLE){
    ((double *)(list->data))[list->num_elements]=val;
    }
    list->num_elements++;
}

double get(arrayList * list, size_t index){
    double retval;
    if(index>=list->num_elements){
        printf("Error: arrayList get index out of range");
        raise(SIGSEGV);
    }
    if(list->type==INT){
        retval=((int*)(list->data))[index];
    }
    if(list->type==FLOAT){
        retval=((float*)(list->data))[index];
    }
    if(list->type==LONG){
        retval=((long*)(list->data))[index];
    }
    if(list->type==DOUBLE){
        retval=((double*)(list->data))[index];
    }
    return retval;
}

推荐答案

向上强制转换C中的数值类型总是可逆的吗?

不,这是实现定义的行为,这是一个非常糟糕的 idea .

我会使用void和一些辅助宏来使其完全通用.它完全与类型无关,可以与任何数据类型(也包括 struct 、联合和数组)一起使用

typedef struct arrayList{
    size_t capacity;
    size_t num_elements;
    size_t elemsize;
    unsigned char data[];
}arrayList;

#define listCreate(capacity, type) reallocateArrayList(NULL, capacity, sizeof(type))
#define listReaaloc(list, capacity) reallocateArrayList(list, capacity, list ? list -> elemsize : 0)
#define listGet(list, object, index) get(list, index, &object)
#define listAdd(list, object) add(list, &object)


arrayList *reallocateArrayList(arrayList * list, size_t capacity, size_t elemsize)
{
    size_t new_num_elements = list ? list -> num_elements : 0;
    
    list = realloc(list, sizeof(*list) + capacity * elemsize * sizeof(list -> data[0]));
    if(list)
    {
        list -> capacity = capacity;
        list -> elemsize = elemsize;
        list -> num_elements = new_num_elements;
    }
    return list;
}

int add(arrayList * list, void *val)
{
    int result = -1;
    if(list && list -> num_elements < list -> capacity)
    {
        memcpy(list -> data + list -> num_elements++ * list -> elemsize, val, list -> elemsize);
        result = 0;
    }
    return result;
}

int get(arrayList * list, size_t index, void *element)
{
    int result = -1;
    if(list && index < list -> num_elements)
    {
        memcpy(element, list -> data + index * list -> elemsize, list -> elemsize);
        result = 0;
    }
    return result;
}

以及一些用法示例:

int main(void)
{
    arrayList *al = listCreate(100, double);
    double dbl = 10.3;

    listAdd(al, (double){4.3});
    listAdd(al, dbl);

    printf("%zu\n", al -> num_elements);

    for(size_t index = 0; index < al -> num_elements; index++)
    {
        double y;
        listGet(al, y, index);
        printf("%f\n", y);
    }

    free(al);
}

https://godbolt.org/z/EYezracjT

C++相关问答推荐

Apple Libm的罪恶功能

如何在C中只使用一个带双方括号([i][j])访问语法的malloc来分配动态大小的2d数组?

为什么输出不是从上到下C

堆栈帧和值指针

为什么在C中二维字符数组会有这样的行为?

自定义应用程序上的日志(log)轮换问题

强制转换变量以在 struct 中蚕食

如何在C-函数中混合使用C代码和ASM?

如何使用FSeek和文件流指针在C中查找文件的前一个元素和前一个减go 一个元素

使用ld将目标文件链接到C标准库

Zlib:解压缩大文件导致";无效代码长度设置";错误

C";中的ANN运行时判断失败#2-变量outputLayer;周围的堆栈已损坏.运行后出错

使用Open62541向OPCUA服务器发送读请求时内存泄漏

合并对 struct 数组进行排序

如何在C中用bool进行文件I/O?

如何编写postgresql支持函数

Ubuntu编译:C中的文件格式无法识别错误

程序打印一些随机空行

free后内存泄漏?

这种 C 函数风格的名称是什么?