我试图通过为matrix
类型提供一些预处理器定义来模拟C语言中的泛型。这是摘录:
#define __matrix_struct(TYPE) \
struct { \
uint32_t sz; \
TYPE **ptr; \
}
#define __matrix_t(TYPE) matrix_ ## TYPE
#define __matrix_ptr_t(TYPE) __matrix_t(TYPE) *
#define __matrix_typedef(TYPE) typedef __matrix_struct(TYPE) __matrix_t(TYPE)
#define __matrix_allocator_name(TYPE) TYPE ## _matrix_alloc
#define __matrix_allocator(TYPE) \
__matrix_ptr_t(TYPE) __matrix_allocator_name(TYPE) (uint32_t sz) { \
uint32_t i; \
__matrix_ptr_t(TYPE) m = (__matrix_ptr_t(TYPE)) malloc(sizeof(__matrix_t(TYPE))); \
m->ptr = (TYPE **) malloc(sz * sizeof(TYPE *)); \
for (i = 0; i < sz; ++i) { \
m->ptr[i] = (TYPE *) calloc(sz, sizeof(TYPE)); \
} \
return m; \
}
#define __matrix_deallocator_name(TYPE) TYPE ## _matrix_free
#define __matrix_deallocator(TYPE) \
void __matrix_deallocator_name(TYPE) (__matrix_ptr_t(TYPE) m) { \
uint32_t i; \
for (i = 0; i < m->sz; i++) { \
free(m->ptr[i]); \
} \
free(m->ptr); \
free(m); \
}
#define matrix_alloc_ptr(TYPE, SIZE) __matrix_allocator_name(TYPE) (SIZE)
#define matrix_dealloc_ptr(TYPE, PTR_NAME) __matrix_deallocator_name(TYPE) (PTR_NAME)
在另一个文件
byte_matrix.h
中,我试图定义一个uint8_t
值矩阵,如下所示:#include "matrix.h"
typedef uint8_t byte;
__matrix_typedef(byte);
__matrix_allocator(byte)
__matrix_deallocator(byte)
尝试编译时,出现以下错误:
CMakeFiles/tictac.dir/game/board.c.o: In function `byte_matrix_alloc':
/home/victor/dev/pc/tictac/game/../matrix/byte_matrix.h:13: multiple definition of `byte_matrix_alloc'
CMakeFiles/tictac.dir/main.c.o:/home/victor/dev/pc/tictac/game/../matrix/byte_matrix.h:13: first defined here
CMakeFiles/tictac.dir/game/board.c.o: In function `byte_matrix_free':
/home/victor/dev/pc/tictac/game/../matrix/byte_matrix.h:14: multiple definition of `byte_matrix_free'
CMakeFiles/tictac.dir/main.c.o:/home/victor/dev/pc/tictac/game/../matrix/byte_matrix.h:14: first defined here
我不明白为什么它会指向同一行并提示该定义,因为我写的每个 header 都包含了保护措施。你能给我解释一下吗?另外,如果您知道解决我问题的更好方法,请告诉我。谢谢。
同样在这种情况下,我需要用
-std=c99
进行编译。 最佳答案
一个快速的解决方法是将static
添加到您的函数定义中。这将在每个引用 header 的编译单元中创建这些函数的静态副本。如果您希望每次都内联函数,这就是方法。
一种替代方法是将函数声明保存在.h文件中,而将实际定义保存在单个.c文件中。这种方法将避免重复,并且编译器不会内联它们(除非您的链接器支持链接时间优化)。
原因是您将此头文件包含在多个编译单元中。在预处理程序完成所有文本替换之后,您最终会在.c文件中得到实际的单独函数定义。而且,如果您未指定希望它们为static
,则默认情况下为extern
,这意味着现在,如果代码的其他部分想要调用它们,则编译器将不知道如何区分它们。
这基本上是在创建头文件时所做的事情:创建声明列表,这些声明将包含在许多编译单元中,但是在单个.c文件中始终只有一个extern定义。