Ошибка множественного определения переменной, которая объявлена ​​и определена в заголовочном файле и используется только в ее файле cpp - PullRequest
1 голос
/ 19 марта 2019

Я нахожусь в процессе переноса кода, написанного для компиляции для одного чипа, в другой чип.

Одна проблема, которая возникает, - это множество ошибок определения.Некоторые из них, по-видимому, связаны с компоновщиком первого чипа, что позволяет мне лениво объявлять переменные extern, когда они будут использоваться в нескольких исходных файлах.Раньше я вообще не использовал extern (объявлял и определял переменную в нечто .h, использовал ее во что-то .cpp и других исходных файлах, которые включали что-то .h), и это компилировалось и связывалось превосходно.

Я считаю, что эти проблемы исправлены достаточно хорошо: теперь мои общие переменные имеют следующий шаблон:

Something.h

extern int foo;

Something.cpp

int foo = 0;

//using foo to do stuff

Main.cpp

#include "Something.h"

//using foo to do stuff

Все хорошо.

Вот кое-что, что я не понимаю, и, похоже, не могу найти ответы здесь или в Google.Я заметил, что те же самые множественные ошибки определения вызваны переменными, которые объявлены и определены в Something.h и использовали only в Something.cpp.

Something.h имеет защиту включения,так что я не думаю, что это связано с тем, что Something.h несколько раз был включен в мою программу.

Ошибка исчезнет, ​​если я объявлю ее как extern и определю ее в файле cpp, но это неправильномне.Я полагаю, что extern не нужен для связи переменной между Something.h и Something.cpp.

Любой совет был бы очень признателен, я бы очень хотел понять, чего мне здесь не хватает.

(Кстати, я компилирую для ESP32, используя Arduino IDE.)

Ответы [ 2 ]

3 голосов
/ 19 марта 2019

Если вы объявите свою переменную в заголовочном файле:

#ifndef GLOBAL_H
#define GLOBAL_H

int foo = 0;

#endif

При каждом включении вашего заголовочного файла или единицы перевода создается новый экземпляр вашего целого числа. Как вы упомянули, чтобы избежать этого, вам нужно объявить элемент как «extern» в заголовочном файле и инициализировать его в файле реализации:

// .h
extern int foo;

// .cpp
int foo = 0

Еще один способ сделать это на C ++ может быть примерно таким:

#ifndef GLOBAL_H
#define GLOBAL_H

struct Global {
    static int foo;
};
#endif

И в вашем файле cpp:

#include "variables.h"

int Global::foo = 0;

C ++ 17 исправляет эту проблему с помощью встроенных переменных, поэтому вы можете сделать:

#ifndef GLOBAL_H
#define GLOBAL_H

inline int foo = 0;

#endif

См. Как работают встроенные переменные? для получения дополнительной информации.

3 голосов
/ 19 марта 2019

Ошибка исчезнет, ​​если я объявлю ее как extern и определю ее в cpp файл

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

Чтобы преодолеть эту проблему, вам нужно либо создать ее в ближайшее время. Пространство имен

something.h

namespace {
  int foo = 0;
}

Или используйте ключевое слово static

something.h

 static int foo = 0;

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

...