簡體   English   中英

_Generic function 在 C 中使用相同的參數重載

[英]_Generic function overloading with same parameters in C

我目前正在制作自己的動態數組,我有 function 將 append 指向它,但我想要 append 我的結構或指針,所以我需要修改 function arguments 而不是 function 名稱。 這是我的 function,它將 append 項放入 ph_arr。

#define ph_array_(type, name) \
    struct name { \
        type* data; size_t used_size, alloc_size; \
    } __attribute__((__packed__))
void ph_array_append_(struct ph_array_void_* ph_arr, size_t data_size, void* items, size_t count);

我想像這樣使用宏( ph_array_append

ph_array_append(ph_arr1, ph_arr2);
// or
const int data[] = { 1, 2, 3, 4 };
ph_array_append(ph_arr1, data, 4);

我不能調用 function 因為我需要為相同的 function 制作不同的 arguments,所以我嘗試添加 function 和調整后的 arguments 但它沒有用,我也嘗試只添加調整后的 88424't6581200 但它沒有要么工作。

是否可以這樣做,還是我必須全部更改? 如果是,你能推薦我一些解決方案嗎?

下面是關於如何根據第二個參數使用_Generic調用不同函數的一個想法,第二個參數是指向struct ph_array_##name的指針或指向 struct 持有的類型的指針。

注意:我使用的是 gcc 擴展名__VA_OPT__

#include <stdio.h>

#define ph_array_(type, name) \
    struct ph_array_##name { \
        type* data; size_t used_size, alloc_size; \
    } __attribute__((__packed__));

// define two structs
ph_array_(void,void)
ph_array_(int,int)

// 2 functions for each struct:
void ph_array_append_void_void(struct ph_array_void *a1, void* items, size_t count, size_t data_size) {
    puts("ph_array_append_void_void");
}
void ph_array_append_void_ph_array_void(struct ph_array_void *a1, struct ph_array_void *a2) {
    puts("ph_array_append_void_ph_array_void");
}
void ph_array_append_int_int(struct ph_array_int *a1, int* items, size_t count) {
    puts("ph_array_append_int_int");
}
void ph_array_append_int_ph_array_int(struct ph_array_int *a1, struct ph_array_int *a2) {
    puts("ph_array_append_int_ph_array_int");
}

// and the _Generic that selects which function to call:
#define ph_array_append(A, S, ...) \
        _Generic((S),                                               \
                        void* : ph_array_append_void_void,          \
        struct ph_array_void* : ph_array_append_void_ph_array_void, \
                         int* : ph_array_append_int_int,            \
         struct ph_array_int* : ph_array_append_int_ph_array_int)   \
        ((A),(S) __VA_OPT__(,) __VA_ARGS__)
        
int main(void) {
    struct ph_array_int foo;
    struct ph_array_void bar;

    ph_array_append(&foo, &foo);
    ph_array_append(&foo, (int*)NULL, 0); // no data_size

    ph_array_append(&bar, &bar);
    ph_array_append(&bar, (void*)NULL, 0, 10); //data_size needed
}

Output:

ph_array_append_int_ph_array_int
ph_array_append_int_int
ph_array_append_void_ph_array_void
ph_array_append_void_void

演示

在 C 中最通用的編程方式仍然是: void* (雖然是_Generic ,它無疑有其用途,但不要將其視為錘子,將其他一切視為釘子)。

例如

struct array_t {
    void *data;       //generic data pointer
    size_t type_size; //sizeof(type)
    size_t size;      //number of elements in data
    size_t capacity;  //allocated size (in number of elements)
};

然后,使用新引入的成員type_size ,您擁有重新分配和復制各種數據 arrays 所需的所有信息。您還可以使用大量 function 指針擴展通用數組,以指定要分配、釋放、復制或移動的適當函數數據(默認為mallocreallocfreememcpymemmove )。

簡單地說,放棄類型安全(使用宏)或使用一堆功能,它們做所有相同的事情但名稱和簽名不同或僅實現通用版本,通過使用void*作為類型參數並通過字段type_size決定分配或移動多少字節。

例如

array_t* array_append(array_t *dst, const array_t *src)
{
    if (dst->type_size != src->type_size) { //incompatible types
        return NULL;
    }
    if (dst->capacity < dst->size + src->size) {
        dst->data = realloc(dst->data, (dst->capacity + src->size) * type_size);
        dst->capacity += src->size;
    }
    memcpy(
        dst->data + (dst->size * dst->type_size),
        src->data,
        src->size * src->type_size
    );
    dst->size += src->size;
    return dst;
}

或者

//param 'num' interpreted as number of elements in 'src',
//therefore the length in bytes of src would be: num * sizeof(type)
//num bytes could also be used here, 
//but then, num would have to be a multiple of dst->type_size,
//therefore num elements recommended
array_t* array_append(array_t *dst, const void *src, size_t num);

這里唯一有用的宏是用於數組初始值設定項或成員訪問(下標、取消引用等),除此之外不需要其他宏或內聯 function 或_Generic voodoo(記住,有人說宏是邪惡的)。

更復雜的版本:

//each type has its own class
struct array_class_t {
    size_t type_size;
    //following sizes, either interpreted as num bytes or num elements,
    //but be consistent, do not mix!
    void* (*allocate)(size_t);
    void* (*reallocate)(void*, size_t);
    void  (*free)(void*);
    void  (*copy)(void*, const void*, size_t);
    void  (*move)(void*, const void*, size_t);
};

struct array_t {
    struct array_class_t *class_;
    void *data;
    size_t size;
    size_t capacity;
};

注意:上面的代碼(指針運算)不符合 C 標准,它使用了 GCC 擴展,參見: Arithmetic on void- and Function-Pointers 為了符合 C 標准,必須將指針強制轉換為unsigned char* (或首先使用,例如代替void* )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM