我试图通过为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
我不明白为什么它会指向同一行的时间并抱怨该定义,因为我写的每个标头都包含防护。你能给我解释一下吗?另外,如果您知道解决我的问题的更好方法,请告诉我。谢谢。
在这种情况下,我还需要使用-std=c99
进行编译。
答案 0 :(得分:3)
一种快速的解决方法是将static
添加到您的函数定义中。这将在每个引用标头的编译单元中创建这些函数的静态副本。如果您希望每次都内联函数,这就是方法。
执行此操作的另一种方法是将函数声明保存在.h文件中,而将实际定义保存在单个.c文件中。这种方法将避免重复,并且编译器不会内联它们(除非您的链接器支持链接时间优化)。
原因是您将此头文件包含在多个编译单元中。在预处理程序完成所有文本替换之后,您最终会在.c文件中得到实际的单独函数定义。而且,如果您未指定希望它们为static
,则默认情况下它们为extern
,这意味着现在,如果代码的其他部分,编译器将不知道如何区分它们想打电话给他们。
这是每次创建头文件时基本上要做的事情:创建一个声明列表,这些声明将包含在许多编译单元中,但是在单个.c文件中始终只有一个extern定义。
答案 1 :(得分:2)
另一种方式(相对于Groo提出的方式)是创建两个宏。
__matrix_allocator_declare
仅具有功能原型-适用于h文件__matrix_allocator_define
,带有功能正文-用于一个(由您选择)c文件这种方法需要处理两个宏,并且不要忘记在某些文件中添加function-body宏,但是(这对于小型微控制器上的嵌入式应用程序来说更重要)保证了只有一个函数实例会消耗内存。