C中只有一次伪通用标头

在对通用向量进行了一些工作后,我询问了这个问题 ,我想知道是否有任何方法可以检查每个类型的库的每个实例只进行一次。

这是当前头文件的样子:

#ifndef VECTOR_GENERIC_MACROS #define VECTOR_GENERIC_MACROS #ifndef TOKENPASTE #define TOKENPASTE(a, b) a ## b #endif #define vector_t(T) TOKENPASTE(vector_t_, T) #define vector_at(T) TOKENPASTE(*vector_at_, T) #define vector_init(T) TOKENPASTE(vector_init_, T) #define vector_destroy(T) TOKENPASTE(vector_destroy_, T) #define vector_new(T) TOKENPASTE(vector_new_, T) #define vector_delete(T) TOKENPASTE(vector_delete_, T) #define vector_push_back(T) TOKENPASTE(vector_push_back_, T) #define vector_pop_back(T) TOKENPASTE(vector_pop_back_, T) #define vector_resize(T) TOKENPASTE(vector_resize_, T) #define vector_reserve(T) TOKENPASTE(vector_reserve_, T) #endif typedef struct { size_t size; size_t capacity; TYPE *data; } vector_t(TYPE); inline TYPE vector_at(TYPE)(vector_t(TYPE) *vector, size_t pos); void vector_init(TYPE)(vector_t(TYPE) *vector, size_t size); void vector_destroy(TYPE)(vector_t(TYPE) *vector); inline TYPE *vector_new(TYPE)(size_t size); inline void vector_delete(TYPE)(vector_t(TYPE) *vector); void vector_push_back(TYPE)(vector_t(TYPE) *vector, TYPE value); inline TYPE vector_pop_back(TYPE)(vector_t(TYPE) *vector); inline void vector_resize(TYPE)(vector_t(TYPE) *vector, size_t size); void vector_reserve(TYPE)(vector_t(TYPE) *vector, size_t size); 

然后可以将标头与源定义一起包括在内:

 #include  #define TYPE int #include "vector.h" #include "vector.def" #undef TYPE int main() { vector_t(int) myVectorInt; vector_init(int)(&myVectorInt, 0); for (int i = 0; i < 10; ++i) vector_push_back(int)(&myVectorInt, i); for (int i = 0; i < myVectorInt.size; ++i) printf("%d ", ++vector_at(int)(&myVectorInt, i)); vector_destroy(int)(&myVectorInt); return 0; } 

我想确保每个TYPE仅包含一次最后endif下面的内容。

显然,#ifde VECTOR_INSTANCE(TYPE)不起作用,所以我真的没有想法……

这是一个问题,但是,当我前一段时间向你提出类似的问题时,我也对此事感兴趣。

我的结论是,如果你要使用许多不同类型的向量(或者使用更准确的命名,动态数组),那么将所有这些函数都转换为vector_##TYPE##_reserve()vector_##type##_resize()等…多次。

相反,使用类型的大小作为额外参数,将这些函数仅在单独的.c文件中定义一次更有效和干净。 这些函数在一个单独的.h文件中进行原型化。 然后,相同的.h文件将提供为您自己的类型生成函数包装器的宏,因此您不会使用该大小作为额外参数来查看它。

例如, vector.h标头将包含以下内容:

 /* Declare functions operating on a generic vector type */ void vector_generic_resize(void *vector, size_t size, size_t data_size); void vector_generic_push_back(void *vector, void *value, size_t data_size); void *vector_generic_pop_back(void *vector, size_t data_size); void vector_generic_init(void *vector, size_t size, size_t data_size); void vector_generic_destroy(void *vector) ; // I don't think data_size is needed here /* Taken from the example in the question */ #define VECTOR_DEFINITION(type)\ typedef struct {\ size_t size;\ size_t capacity;\ type *data;\ } vector_ ## type ## _t;\ /* Declare wrapper macros to make the above functions usable */ /* First the easy ones */ #define vector_resize(vector, size) vector_generic_resize(vector, size, sizeof(vector.data[0])) #define vector_init(vector, size) vector_generic_init(vector, size, sizeof(vector.data[0])) /* Type has to be given as an argument for the cast operator */ #define vector_pop_back(vector, type) (*(type*)(vector_generic_pop_back(vector, sizeof(vector.data[0])))) /* This one is tricky, if 'value' is a constant, it's address cannot be taken. I don't know if any better workarround is possible. */ #define vector_push_const(vector, type, value) \ { \ type temp = value; \ vector_generic_push_back(vector, &temp, sizeof(vector.data[0]));\ } /* Equivalent macro, but for pushing variables instead of constants */ #define vector_push_var(vector, value) vector_generic_push_back(vector, &value, sizeof(vector.data[0])) /* Super-macro rediriging to constant or variable version of push_back depending on the context */ #define GET_MACRO(_1,_2,_3,NAME,...) NAME #define vector_push_back(...) GET_MACRO(__VA_ARGS__, vector_push_const, vector_push_var)(__VA_ARGS__) /* This macro isn't really needed, but just for homogenity */ #define vector_descroy(vector) vector_generic_destroy(vector) 

然后可以按照您在链接的示例中所说的那样使用这些函数,其中包含vector_generic_push_back的重要例外,遗憾的是每次都必须将该类型指定为额外的宏参数。

所以用这个解决方案

  • 您只需在.c文件中执行VECTOR_DEFINITION() ,避免两次使用相同类型声明它的风险
  • 矢量库仅在二进制文件中存在一次
  • 除了pop back宏和push literal宏之外,可以优雅地使用宏而不使用其名称中的类型。
  • 如果这是一个问题,你可以使推文字长期使用很长时间,它会工作但可能会松散效率。
  • 类似地,你可以使pop_back()宏和vector_generic_pop_back()函数不像它们在C ++语言中那样返回任何内容,因此如果你同时执行这两个技巧,则永远不需要在宏中明确使用类型名称。

作为参考,您在问题中链接的示例中发布的主要function必须进行调整:

  #include  #include  #include "vector.h" typedef unsigned int uint; typedef char* str; VECTOR_DEFINITION(uint) VECTOR_DEFINITION(str) int main() { vector_uint_t vector; vector_init(&vector, 10); for (unsigned int i = 0; i < vector.size; ++i) vector.data[i] = i; for (unsigned int i = 0; i < 10; ++i) vector_push_back(&vector, i); /* When pushing back a constant, we *have* to specity the type */ /* It is OK to use C keywords as they are supressed by the preprocessor */ vector_push_back(&vector, unsigned int, 12); for (unsigned int i = 0; i < vector.size; ++i) printf("%d ", vector.data[i]); printf("\n"); vector_destroy(&vector); vector_str_t sentence; vector_init(&sentence, 0); vector_push_back(&sentence, "Hello"); vector_push_back(&sentence, str, "World!"); /* Also possible, less efficient */ vector_push_back(&sentence, "How"); vector_push_back(&sentence, "are"); vector_push_back(&sentence, "you?"); for (unsigned int i = 0; i < sentence.size; ++i) printf("%s ", sentence.data[i]); printf("\n"); vector_destroy(&sentence); return 0; } 

建议:

从vector.h文件中删除原型。

将原型放在vector.def文件的顶部。

从vector.h文件中删除typedef结构

将typedef结构放在vector.def文件中的原型之前。

然后,对于vector.h文件,多次#include语句将没有任何不良影响。

然后在每个要使用这些向量类型的源文件中使用以下内容:

 #include #define TYPE int #include #undef TYPE #define TYPE char #include #undef TYPE ... etc BTW: There is no library involved, so I'm a bit confused by the reference to 'library' in the question It may be worthwhile to also prefix the 'static' modifier to each of the function definitions so the definitions are not visible across source files It may be worthwhile to use parens around the parameters to TOKENPASTE so modifiers like 'static' and.or 'const' can be prefixed to the function names.