在同一个地方有多个功能定义

时间:2018-11-16 10:24:54

标签: c c99 generic-programming

我试图通过为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进行编译。

2 个答案:

答案 0 :(得分:3)

一种快速的解决方法是将static添加到您的函数定义中。这将在每个引用标头的编译单元中创建这些函数的静态副本。如果您希望每次都内联函数,这就是方法。

执行此操作的另一种方法是将函数声明保存在.h文件中,而将实际定义保存在单个.c文件中。这种方法将避免重复,并且编译器不会内联它们(除非您的链接器支持链接时间优化)。

原因是您将此头文件包含在多个编译单元中。在预处理程序完成所有文本替换之后,您最终会在.c文件中得到实际的单独函数定义。而且,如果您未指定希望它们为static,则默认情况下它们为extern,这意味着现在,如果代码的其他部分,编译器将不知道如何区分它们想打电话给他们。

这是每次创建头文件时基本上要做的事情:创建一个声明列表,这些声明将包含在许多编译单元中,但是在单个.c文件中始终只有一个extern定义。

答案 1 :(得分:2)

另一种方式(相对于Groo提出的方式)是创建两个宏。

  • __matrix_allocator_declare仅具有功能原型-适用于h文件
  • __matrix_allocator_define,带有功能正文-用于一个(由您选择)c文件

这种方法需要处理两个宏,并且不要忘记在某些文件中添加function-body宏,但是(这对于小型微控制器上的嵌入式应用程序来说更重要)保证了只有一个函数实例会消耗内存。