После компилируется без ошибок:
extern "C" void func( void );
extern void func( void );
Если я изменю порядок объявлений,
extern void func( void );
extern "C" void func( void );
Я получаю ошибку компилятора: conflicting declaration of ‘void func()’ with ‘C’ linkage
.
Стандарт С++ говорит:
В обоих случаях это одна и та же функция. Я предполагаю, что компилятор С++ хранит внутри сигнатуры функций, которые он будет компилировать. В первом примере компилятор считает второе объявление допустимым и использует первое объявление для компиляции. Во втором примере это не так. Он пересматривает обе декларации как разные декларации.
Какие технические детали стоят за этим?
gcc 9.4.0 и msvc 19.29.30147
В идеале все они должны иметь одинаковую подпись. Почему различия? Разве это не может быть определено в заголовочном файле, на который могут ссылаться оба экземпляра?
Зачем вообще нужен один func
с привязкой к C++?
@tadman Второй без extern "C"
разрешен, потому что это вариант реализации в .c, где extern "C"
недействителен.
@ 273K Я не говорю, что это не разрешено, но это непоследовательно, и это первый шаг на пути к таким проблемам. Если это создается в контексте C, вы правы, это будет проблемой, но это можно решить с помощью некоторой магии #ifdef
в единственном заголовочном файле, который определяет это.
Первое обнаруженное объявление extern
определяет связь; вы не можете изменить связь после первоначального объявления.
То есть первое эквивалентно extern "C" void func( void ); extern "C" void func( void );
, второе — extern "C++" void func( void ); extern "C" void func( void );
Я хотел бы понять, что вызывает ошибку, а не то, как это должно быть сделано. Я очень хорошо знаю, как это должно быть сделано. Это удивительный вопрос компилятора С++. Не то, как это должно быть сделано или что вы не понимаете. Я ясно сказал: я не понимаю, почему изменение порядка двух объявлений вызывает ошибку компилятора?
Повторное объявление функции не требуется для повторения ее спецификации связи. По языковой привязке от cppreference:
Функция может быть повторно объявлена без спецификации привязки после того, как она была объявлена со спецификацией языка, второе объявление будет повторно использовать первую привязку к языку. Обратное неверно: если первое объявление не имеет языковой привязки, предполагается
"C++"
, а повторное объявление с другим языком является ошибкой.
В первом фрагменте вы объявляете функцию с привязкой "C"
, а затем повторно объявляете ее без явной привязки. Это нормально; исходная связь предполагается. Однако во втором фрагменте вы объявляете функцию с (неявной) связью "C++"
, а затем пытаетесь повторно объявить ее с помощью связи "C"
— это конфликт, отсюда и ошибка.
Это именно то, что я искал. Часть ссылки на cpp, которая объясняет, почему важен порядок объявления. Ответ в «Противоположное неверно:»
Что вы не понимаете?