Я любил бы справку, диагностируя источник дублирующейся ошибки символа, которую я получаю, когда я пытаюсь скомпилировать с g ++ 4.2.1.
Определенная ошибка
ld: duplicate symbol _SOCIODEM_FILENAMES in /var/folders/c+/c+eq1Qz1Feye7vxs5mQOUE+++TI/-Tmp-//ccP3yVgF.o and /var/folders/c+/c+eq1Qz1Feye7vxs5mQOUE+++TI/-Tmp-//cc1NqtRL.o
collect2: ld returned 1 exit status
Ошибка происходит только, когда я включаю это объявление в названный файл Parameters.h
:
// Parameters.h
#ifndef PARAMETERS_H
#define PARAMETERS_H
// ...[code snipped]...
const int NUM_SOCIODEM_FILES = 5;
const char * SOCIODEM_FILENAMES[ NUM_SOCIODEM_FILES ] = { "LSPAN_PDF.txt",
"FLEDGE_PDF.txt",
"PAIR_PDF.txt",
"BIRTH_AGE_PDF.txt",
"SPLIT_PDF.txt" };
// ...[code snipped]...
#endif
Я искал все свои файлы, и это - единственное место где SOCIODEM_FILENAMES
объявляется. Когда я комментирую объявление, 'дублирующийся символ' ошибка уходит.
Я незнаком с ошибками компоновщика (если это - то, что это), и ценил бы справку, диагностирующую проблему. Все мои заголовочные файлы имеют #ifndef...#define...#endif
обертки. Моя команда компиляции
g++ -o a.out -I /Applications/boost_1_42_0/ Host.cpp Simulation.cpp main.cpp Rdraws.cpp
Заранее спасибо.
Сводка решения
Я теперь имею в Parameters.h:
const char * const SOCIODEM_FILENAMES[ NUM_SOCIODEM_FILES ] = { "LSPAN_PDF.txt",
"FLEDGE_PDF.txt",
"PAIR_PDF.txt",
"BIRTH_AGE_PDF.txt",
"SPLIT_PDF.txt" };
Все другие определения и объявления в Parameters.h неизменны. Andrey и другие комментаторы суммируют альтернативное использование подхода extern
, который является излишеством в моих целях.
По какой-то причине ни один из ответов до сих пор не помог объяснить разницу между вашим целочисленным NUM_SOCIODEM_FILES
объектом и объектом массива SOCIODEM_FILENAMES
. Последний запускает ошибку компоновщика по уже объясненным причинам: потому что вы включаете файл заголовка в несколько файлов реализации. Тем не менее, первый будет связываться без каких-либо проблем (потому что действительно нет проблем с объявлением NUM_SOCIODEM_FILES
). Почему?
Причина в том, что ваш объект NUM_SOCIODEM_FILES
объявлен const
. В C ++ объекты const имеют внутреннюю связь по умолчанию, что означает, что они не вызывают проблем при связывании, даже если они определены в нескольких файлах реализации. Другими словами, в C ++ ваш NUM_SOCIODEM_FILES
эквивалентен
static const int NUM_SOCIODEM_FILES = 5; /* internal linkage */
, поэтому это не приводит к каким-либо проблемам со связью.
В то же время ваш SOCIODEM_FILENAMES
не объявлен константой, поэтому он получает внешнюю ссылку по умолчанию и в конечном итоге приводит к ошибкам компоновщика. Но если вы объявите свой SOCIODEM_FILENAMES
как const
, проблема исчезнет
const char * const SOCIODEM_FILENAMES[ NUM_SOCIODEM_FILES ] = {
...
Обратите внимание, где в объявлении помещается дополнительный const
. Если вы просто добавите этот дополнительный const
и оставите все остальное как есть (т.е.сохраните определение, если SOCIODEM_FILENAMES
в файле заголовка), компоновщик не сообщит об ошибке, даже если вы включите файл заголовка в несколько единиц перевода.
Это не рекомендуемый подход, так как таким образом вы предоставите внутреннюю ссылку SOCIODEM_FILENAMES
и получите автономную копию массива SOCIODEM_FILENAMES
в каждой единице перевода - что-то, что может работать нормально, но все еще имеет очень мало смысла. Итак, для вашего массива обычно лучше использовать подход extern
, рекомендованный в других ответах.
Однако учтите, что обычно вы не должны делать это для объявления NUM_SOCIODEM_FILES
!!! Это нормально, как есть, определено в файле заголовка. Если вы не пытаетесь сделать что-то необычное, скалярные константы обычно должны быть определены с инициализатором в файлах заголовков - таким образом они могут рассматриваться как константы времени компиляции во всех единицах перевода, что является довольно ценной вещью. иметь. Итак, остерегайтесь странного совета, присутствующего в некоторых других ответах, чтобы переместить определение NUM_SOCIODEM_FILES
в файл .cpp
- на самом деле это не имеет смысла и является совершенно неправильным поступком. .
Скорее всего, вы #include
включаете этот файл в несколько исходных файлов. Проблема в том, что каждое включение приводит к отдельному определению переменной с именем SOCIODEM_FILENAMES
. Защиты включения не помогают справиться с этой проблемой. Защиты включения предотвращают множественные объявления в пределах одной единицы компиляции; они не предотвращают множественные определения в нескольких единицах компиляции.
Что вам нужно сделать, так это объявить эти переменные как extern
в заголовке, а затем определить их ровно в одном исходном файле. например,
// Parameters.h
#ifndef PARAMETERS_H
#define PARAMETERS_H
// ...[code snipped]...
extern const int NUM_SOCIODEM_FILES;
extern const char * SOCIODEM_FILENAMES[];
// ...[code snipped]...
#endif
и затем:
// Parameters.cpp (or some other source file)
const int NUM_SOCIODEM_FILES = 5;
const char * SOCIODEM_FILENAMES[ NUM_SOCIODEM_FILES ] = { "LSPAN_PDF.txt",
"FLEDGE_PDF.txt",
"PAIR_PDF.txt",
"BIRTH_AGE_PDF.txt",
"SPLIT_PDF.txt" };
Вы можете обойтись без этого для int
, потому что это постоянное целое число, и поэтому компилятор может просто рассматривать его как константу времени компиляции, и оно никогда даже не появится в скомпилированном коде. Однако с char*
так обращаться нельзя, поэтому он должен иметь ровно одно определение (в C++ это известно как "правило одного определения").
Защита заголовков (#ifndef..#endif
обертка) просто предотвращает включение одного и того же заголовка несколько раз в один исходный файл. Вы все равно можете иметь несколько исходных файлов, включающих этот заголовок, и каждый из них будет объявлять этот символ отдельно. Поскольку все они имеют одно и то же имя, соединение этих исходников вместе приведет к столкновению имен символов. Возможно, вы захотите объявить символ в исходном файле, а не в заголовочном
Проблема в том, что вы помещаете определение в заголовочный файл. Если вы включите этот файл в более чем одну единицу компиляции (файл .cpp), вы фактически создадите несколько определений, и во время компоновки вы получите эту ошибку.
Вам нужно поместить оба этих определения в файл .cpp и поместить только объявление в заголовочный файл:
extern const int NUM_SOCIODEM_FILES;
extern const char * SOCIODEM_FILENAMES[];
Как предлагали другие, один из способов сделать это - объявить NUM_SOCIODEM_FILES
и SOCIODEM_FILENAMES
как extern
и определить их один раз во внешнем файле.Другой способ - объявить их как static
- это приведет к их дублированию в каждом объектном файле, который включает заголовок, но не вызовет ошибки, поскольку определение является частным для этого объектного файла. Какой вариант вы выберете, полностью зависит от ваших предпочтений.