Локальная функция определена с одинаковой сигнатурой в двух файлах cpp.Почему они должны быть видны друг другу? - PullRequest
1 голос
/ 15 февраля 2012

Почему в Eclipse появляется ошибка, связанная с наличием двух определений одной и той же функции:

int readPath(const String &destDir, String &pathToFile) {/*Filler*/}

Одна - это старая (или новая) версия, которую я временно отбросил, чтобы сосредоточиться на другой версии.Я хотел бы снова сохранить его в каталоге моего проекта.

Я могу переместить его, но я не думаю, что это правильно, что идентификаторы в файле cpp могут рисковать именованием коллизий с идентификаторами в других файлах cpp, если только вына самом деле #include с этими файлами cpp, а я нет.

Ответы [ 3 ]

3 голосов
/ 15 февраля 2012

Меня больше волнует, почему это должно произойти

Потому что так работает C ++ (и C).

Это:

int readPath(const String &destDir, String &pathToFile);

Является объявлением функции. Он сообщает компилятору: «Где-то в моем коде, в этом или другом модуле перевода будет существовать функция с именем readPath, которая принимает в качестве аргументов ...» Это то, что вы помещаете в заголовочные файлы.

Это:

int readPath(const String &destDir, String &pathToFile) {/*Filler*/}

Является ли функция определение . Определения не просто говорят компилятору, что что-то «будет существовать». Он сообщает компилятору, что он существует здесь , и вот как он работает.

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

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

Функции и переменные по умолчанию имеют external linking. Это, безусловно, самый распространенный случай. Ключевое слово static используется для предоставления функций и переменных внутренняя связь.

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

Правило ODR смягчается при использовании функций inline. Они могут быть определены в нескольких единицах перевода, но только если реализация одинакова для всех.

Одна - это старая (или новая) версия, которую я временно сбросил, чтобы сосредоточиться на другой версии. Я хотел бы снова сохранить его в каталоге моего проекта.

Вот ваши варианты:

  1. Определить функции в анонимном пространстве имен (пространстве имен без имени). По определению C ++ все анонимные пространства имен имеют уникальные имена. Поэтому невозможно, чтобы символы, определенные в двух разных анонимных пространствах имен, конфликтовали.
  2. # определение вокруг старой реализации. Используйте #ifdef, чтобы отключить его. Это проверенная временем техника для сохранения старого кода.
  3. Выйдите из темных веков и научитесь использовать контроль версий . Старый код принадлежит к предыдущим версиям файлов, теперь не загромождает ваши файлы. Если вы хотите найти их снова, отметьте эти файлы и ревизии.
2 голосов
/ 15 февраля 2012

Вы нарушаете одно правило определения .

Каждая единица перевода (файлы реализации + включает) генерирует объектный файл.Этот объектный файл содержит все экспортированные символы.Метод, поскольку он определен в модуле перевода, будет экспортирован в оба объектных файла.Ergo - ошибка.

Если вы должны иметь один и тот же прототип функции, который определяется по-разному в нескольких файлах реализации, вы можете

  • добавить функцию к namespace - он может быть анонимным, если нет необходимости давать ему имя.
  • объявлять его как static, что дает ему внутреннюю связь.
1 голос
/ 15 февраля 2012

Вы по-прежнему путаете компоновщик, если один символ ("readpath") доступен дважды.

Это можно исправить, изменив связь одной из двух функций с extern на intern (илинет), поместив его в анонимное пространство имен или объявив его static.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...