C++ включает защиту и множественные ошибки определения

У меня есть ситуация, когда мне нужно включить файл заголовка (stack.h) в 2 файла .cpp.

Настройка выглядит следующим образом:

//------"stack.h"------//
std::stack<int> s;
int a;
void doStackOps();
void print();

//------"stack.cpp"------//
#include "stack.h"


//------"main.cpp"------//
#include "stack.h"

Вопрос 1

Мой заголовочный файл содержит 2 переменные и 2 метода. Кажется, я получаю несколько ошибок определения только для переменных, почему это так? Не следует ли также жаловаться на переопределение функций?

Ошибка выглядит так:

duplicate symbol _stacks in:
/Users/.....stack.o
/Users/......main.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

вопрос 2

Чтобы решить эту проблему, ответ, предложенный для аналогичной ситуации, здесь -symbol/28652792#28652792">Почему моя защита включения не предотвращает рекурсивное включение и множественные определения символов? это то, что мы используем

inline or static 

где предпочтительнее встроенный

  • Почему встроенный предпочтительнее статического?
  • inline может использоваться только с функциями?

Поскольку я получаю ошибку только в переменной, ошибка исчезает, когда я переопределяю стек как:

static std::stack<int> s; 
static int a; 

Любые идеи о том, что может происходить здесь? Если это поможет, я использую Xcode 6. Буду очень признателен за любую помощь!

Заранее спасибо.


person ggog    schedule 23.02.2015    source источник
comment
Вы знаете, что делает static? (когда вне функции или класса)   -  person user253751    schedule 23.02.2015
comment
Это два определения переменных и два объявления функций. Переобъявления в порядке.   -  person chris    schedule 23.02.2015
comment
@immibis: он выделяет одну часть памяти во время компиляции для переменной, поэтому не будет других экземпляров или переопределений. Итак, я понимаю, почему статика будет работать.   -  person ggog    schedule 23.02.2015
comment
@chris: я вижу ошибку, которая считывает повторяющийся символ для архитектуры x86_64. Он находит один и тот же символ в main.o и stack.o, если я не добавляю ключевое слово static для переменных.   -  person ggog    schedule 23.02.2015
comment
@ggog Нет, совершенно неправильно. Это означает, что переменная имеет файловую область.   -  person user253751    schedule 23.02.2015
comment
Вам, вероятно, не нужно, чтобы эти переменные были глобальными переменными в первую очередь.   -  person chris    schedule 23.02.2015


Ответы (1)


Есть несколько ошибок определения, потому что stack.cpp делает:

stack<int> s;

и main.cpp также определяет стек:

stack<int> s;

У вас есть два разных глобальных объекта, определенных с одним и тем же именем, что вызывает неопределенное поведение (к счастью, ваш компоновщик диагностирует это).

Вместо этого вы, вероятно, намеревались иметь один стек, на который ссылаются несколько разных модулей. Для этого вы можете сделать так, чтобы строка, определяющая стек, появлялась только один раз. (Помните, что #include — это обычная замена текста; ваш код ведет себя так же, как если бы вы копировали и вставляли содержимое stack.h в тело каждого файла .cpp).

У других модулей должна быть строка, в которой говорится: «Где-то (но не здесь) определен stack<int> с именем s», и код для этого:

extern stack<int> s;

Поэтому вы должны поместить эту строку в свой заголовочный файл и поместить stack<int> s; ровно в один файл .cpp - неважно, в какой.


В случае с функциями вы не определяете никаких функций в заголовке, только объявляете. Если вы определили функцию в заголовке (например, void print() { }), то у вас будет такая же ошибка множественного определения, вызывающая неопределенное поведение.

person M.M    schedule 23.02.2015
comment
Это имеет смысл. Предположим, я объявляю нижеследующее в main.cpp extern stack‹int› s; Затем main.cpp будет заполнен всеми переменными в проекте, объявленными как внешние, чего я не хочу. Я думаю, что нахожусь в этой ситуации из-за настройки моего проекта. Не могли бы вы предложить, как должен быть структурирован мой проект? В настоящее время проект представляет собой dataStructures &files-stack.cpp, stack.h, quickSort.cpp,quickSort.h,mergeSort.cpp,mergeSort.h. main.cpp включает все .h, и я могу вызвать любой алгоритм. Что было бы правильно иметь один проект, в котором есть все эти файлы. Предложения? - person ggog; 23.02.2015
comment
@ggog я не уверен, что ты имеешь в виду. Я описал в своем ответе, куда все должно идти. Неважно, виден ли extern в юните, который его не использует. - person M.M; 23.02.2015