[英]_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 指針擴展通用數組,以指定要分配、釋放、復制或移動的適當函數數據(默認為malloc
、 realloc
、 free
、 memcpy
、 memmove
)。
簡單地說,放棄類型安全(使用宏)或使用一堆功能,它們做所有相同的事情但名稱和簽名不同或僅實現通用版本,通過使用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.