Множественное определение функции в одном месте - PullRequest
0 голосов
/ 16 ноября 2018

Я пытаюсь смоделировать обобщения в C, имея некоторые определения препроцессора для типа matrix. Вот выдержка из этого:

#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 голосов
/ 16 ноября 2018

Другой способ (относительно предложенного Groo) - создать два макроса.

  • __matrix_allocator_declare только с прототипом функции - для h-файла (ов)
  • __matrix_allocator_define с телом функции - за один (выбранный вами) c-файл

Этот способ требует обработки двух макросов и не забывает добавить макрос тела функции в некоторый файл, но (и это более важно для встроенных приложений на небольших микроконтроллерах) он гарантирует, что только один экземпляр функции будет занимать память.

0 голосов
/ 16 ноября 2018

Быстрое решение проблемы - добавить static в определения вашей функции. Это создаст статическую копию этих функций в каждом модуле компиляции, который ссылается на заголовок. Если вы хотите, чтобы функции были встроены каждый раз, это путь.

Альтернативный способ сделать это - сохранить объявления функций в файле .h, а фактические определения - в одном файле .c. Этот подход позволит избежать дублирования, и компилятор не будет их встроять (если только ваш компоновщик не поддерживает оптимизацию времени ссылки).

Причина в том, что вы включаете этот заголовочный файл в несколько модулей компиляции. После того, как препроцессор выполнит все текстовые замены, вы получите фактические отдельные определения функций внутри ваших .c файлов. И если вы не укажете, что хотите, чтобы они были static, они по умолчанию extern, что означает, что теперь компилятор не знает, как их дифференцировать, если какая-то другая часть кода хочет вызвать их .

Это то, что вы в основном делаете, когда создаете заголовочный файл: вы создаете список объявлений, которые будут включены во многие модули компиляции, но всегда есть одно внешнее определение в одном файле .c.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...