У меня есть ситуация, строящая кодовую базу C с помощью компилятора C ++, которая параллельна этому:
lib.h
extern int const values[2] = {1, 2};
lib.c
#include "lib.h"
main.c
#include <iostream>
extern int const values[2];
int main() {
std::cout << values[0] << ":" << values[1] << std::endl;
}
Я должен был добавить внешний вид из-за чего-то, указанного в C ++ 03 Стандартное приложение C Совместимость C.1.2 Пункт 3. (Компиляция с -fpermissive
смести это под коврик.)
Между прочим, разница в том, как values
появляется в objdump, как это до extern
:
$ objdump -t lib.o | grep values
0000000000000000 l O .rodata 0000000000000008 _ZL6values
$ objdump -t main.o | grep values
0000000000000000 *UND* 0000000000000000 values
…и затем это так после того, как он добавлен:
$ objdump -t lib.o | grep values
0000000000000000 g O .rodata 0000000000000008 values
$ objdump -t main.o | grep values
0000000000000000 *UND* 0000000000000000 values
Таким образом, искажение имени было удалено, мы видим, что буква «L» превращается в букву «G», и компоновщик не жалуется на values
быть неопределенным.
Теперь представьте ту же ситуацию с двумя очень похожими файлами, измененными таким же образом:
ТМП-exttypes.h
extern const REBYTE Reb_To_RXT[REB_MAX] = { /* bunch of stuff */ };
а-lib.c
extern const REBYTE Reb_To_RXT[REB_MAX];
Это только два определения Reb_To_RXT в проекте, построенных чисто. Но это не связывание, и когда я objdump только два файла, которые упоминают это, я получаю:
$ objdump -t a-lib.o | grep Reb_To_RXT
00000000 *UND* 00000000 Reb_To_RXT
$ objdump -t f-extension.o | grep Reb_To_RXT
00000080 l O .rodata 00000038 _ZL10Reb_To_RXT
Это говорит L, и это название искажено. Что не сделало гораздо более простой пример счастливым. Но мне интересно, как это могло случиться с экстерьером при каждом появлении. Правильно ли я считаю, что это дымящийся пистолет … и разве не должно случиться, что что-то, только объявленное как extern, не должно иметь где-либо локальную связь?
я не могу понять, что ты просить.
но …
имеющий
extern int const values[2] = {1, 2};
в заголовочном файле у вас есть UB, если этот заголовок включен в более чем одну единицу перевода. скорее всего, но не обязательно, вы получите ошибку компоновки.
одно решение: объявить массив в заголовке, как
extern int const values[2];
но определите его (с инициализатором) в файле реализации.
Другое решение состоит в том, чтобы использовать шаблонный трюк или трюк встроенных функций для определения массива в заголовочном файле.
уловка встроенной функции:
typedef int const Values[2];
inline Values& valuesRef()
{
static Values theValues = {1, 2};
return theValues;
}
static Values& values = valuesRef();
Да исправить.
Файл, который вы (я) редактировали, был автоматически сгенерирован и фактически уничтожен чистым изготовителем, который был замечен на полпути при записи мыслительного процесса. Эта «tmp», которую вы видите в этом конкретном заголовке, должна была указывать на «временный, не редактировать», и если файл не перезагружается в редакторе, который вы используете, он может сбить с толку.
(Закончил ход мыслей в любом случае для институциональных знаний. :-P)