Найден один или несколько многократно определенных символов

DebugUtil.h

#ifndef DEBUG_UTIL_H #define DEBUG_UTIL_H #include  int DebugMessage(const char* message) { const int MAX_CHARS = 1023; static char s_buffer[MAX_CHARS+1]; return 0; } #endif 

Когда я пытаюсь запустить это, я получаю эту ошибку:

Terrain.obj: ошибка LNK2005: «int __cdecl DebugMessage (char const *)» (? DebugMessage @@ YAHPBD @ Z), уже определенный в Loodus.obj

Renderer.obj: ошибка LNK2005: «int __cdecl DebugMessage (char const *)» (? DebugMessage @@ YAHPBD @ Z), уже определенный в Loodus.obj

test.obj: ошибка LNK2005: «int __cdecl DebugMessage (char const *)» (? DebugMessage @@ YAHPBD @ Z), уже определенный в Loodus.obj

C: \ Users \ Tiago \ Desktop \ Loodus Engine \ Debug \ Loodus Engine.exe: фатальная ошибка LNK1169: найден один или несколько множимых символов

Но почему это происходит? У меня есть #ifndef #define и #endif в заголовке, поэтому несколько определений не должно происходить

Поместите определение (тело) в файл cpp и оставьте только объявление в файле ah. Включите защитные устройства, работающие только в пределах одной единицы перевода (как исходный файл), а не во всей вашей программе.

Правило одного определения стандарта C ++ утверждает, что должно отображаться ровно одно определение каждой не-встроенной функции, которая используется в программе. Таким образом, еще одна альтернатива – сделать вашу функцию встроенной.

Сделайте функцию inline или объявите функцию в файле заголовка и определите ее в файле cpp.

 inline int DebugMessage(const char* message) { const int MAX_CHARS = 1023; static char s_buffer[MAX_CHARS+1]; return 0; } 

РЕДАКТИРОВАТЬ:

Как отмечает Tomalak Geret’kal, лучше использовать мои последние предложения, чем мои прежние, и перенести объявление функции в файл cpp.

(Предполагая, что опубликованный код является заголовком, включенным в несколько файлов .cpp)

Защитники заголовков не защищают вас от множественных определений ссылок. Независимо от того, что вы обеспечили, чтобы заголовок появлялся только один раз для единицы перевода, если у вас более одного модуля перевода, это все еще несколько определений.

Напишите определения в исходных файлах и только объявления в заголовках.

Единственными исключениями являются inline функции, функции, определенные в определении class (хотя это не рекомендуется!) И шаблоны функций.

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

Вы можете сделать несколько вещей:

  1. Переместите определение в файл .cpp и сохраните только объявление в заголовке.
  2. Используйте анонимное пространство имен вокруг функции в вашем файле заголовка (но понимайте, что это взломать – у вас все еще будет несколько определений, просто нет столкновения имен).
  3. Отметьте его как встроенный (хотя он может не всегда работать – только если компилятор действительно хочет его встроить). Это также взломать по той же причине, что и выше.

Переместите определение в файл .cpp.

Объявите свои функции в файлах на C ++. Поскольку вы определили свою функцию в файле заголовка, и этот файл заголовка включен из нескольких исходных файлов, он определяется для каждого исходного файла, который включает его. Вот почему это сообщается как определено в нескольких местах.

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

Похоже, что вы включаете DebugUtil.h в несколько единиц перевода, а затем соединяете эти объекты вместе. Тем не менее, DebugUtil.h предоставляет определение функции DebugMessage, так что определение существует во всех единицах перевода, которые включали заголовок. В результате, когда вы связываете объекты, компоновщик справедливо жалуется, что символ многократно определен.

Измените DebugUtil.h так, чтобы он декларировал DebugMessage через прототип, но не дал определения и поместил определение DebugMessage в файл .c, который вы будете компилировать и связать с другими объектами.

Это предотвращает только множественные включения в одном исходном файле; несколько исходных файлов #include ing все равно будут генерировать несколько определений DebugMessage() . В общем, вы должны либо не размещать функции в файлах заголовков вообще, либо сделать их static (и обычно inline , так как в противном случае обычно не имеет смысла иметь несколько static определений одной и той же функции).

100% Вы правильно включили гвардейцев, но все еще получаете ошибку переопределения?

Для Visual Studio: я был очень расстроен, потому что я был правильно включен охранниками, но только для выяснения проблемы была визуальная студия. Если вы добавили файл в свой проект, компилятор добавит файл дважды, даже если у вас есть защита от файла реализации и файла заголовка.

Если вы не используете эксклюзивную визуальную студию и говорите … иногда используйте code :: blocks, вы можете захотеть только # включить файл, если обнаружите отсутствие среды визуальной студии.

 DebugUtil.h : ---------------------- #ifndef _WIN32 #include "DebugUtil.c" #endif ---------------------- 

Если у вас все в порядке, включая stdio.h, вы можете быть немного менее хакерскими:

 DebugUtil.h : ---------------------- #include  #ifdef _MSC_VER #include "DebugUtil.c" #endif ---------------------- 

Ссылка: предопределенные macros, Visual Studio: https://msdn.microsoft.com/en-us/library/b0084kay.aspx

  • Единичное тестирование и проверка значения частной переменной
  • одновременное чтение и запись файла в C #
  • printf не печатать на экране
  • Почему выражение вызова метода имеет тип динамический, даже если существует только один возможный тип возврата?
  • Использование побитовых операторов для булевых языков в C ++
  • Утверждение времени компиляции?
  • Является ли 2d-массив двойным указателем?
  • Перенаправление вывода exec в буфер или файл
  • Можно ли выделить функцию внутри массива и вернуть ее с помощью ссылки?
  • Неопределенные символы для архитектуры x86_64 - Mavericks (Yosemite, El Capitan ...)
  • Как я могу сделать `new ` default-initialize массив примитивных типов?
  • Давайте будем гением компьютера.