Конфликтующее объявление функции со связью «C»

После компилируется без ошибок:

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.
Стандарт С++ говорит:

  • Не более одной функции с определенным именем может быть связь "C" (независимо от пространства имен).

В обоих случаях это одна и та же функция. Я предполагаю, что компилятор С++ хранит внутри сигнатуры функций, которые он будет компилировать. В первом примере компилятор считает второе объявление допустимым и использует первое объявление для компиляции. Во втором примере это не так. Он пересматривает обе декларации как разные декларации.
Какие технические детали стоят за этим?
gcc 9.4.0 и msvc 19.29.30147

Что вы не понимаете?

273K 13.02.2023 17:17

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

tadman 13.02.2023 17:19

Зачем вообще нужен один func с привязкой к C++?

Ted Lyngmo 13.02.2023 17:22

@tadman Второй без extern "C" разрешен, потому что это вариант реализации в .c, где extern "C" недействителен.

273K 13.02.2023 17:22

@ 273K Я не говорю, что это не разрешено, но это непоследовательно, и это первый шаг на пути к таким проблемам. Если это создается в контексте C, вы правы, это будет проблемой, но это можно решить с помощью некоторой магии #ifdef в единственном заголовочном файле, который определяет это.

tadman 13.02.2023 17:23

Первое обнаруженное объявление extern определяет связь; вы не можете изменить связь после первоначального объявления.

molbdnilo 13.02.2023 17:24

То есть первое эквивалентно extern "C" void func( void ); extern "C" void func( void );, второе — extern "C++" void func( void ); extern "C" void func( void );

molbdnilo 13.02.2023 17:30

Я хотел бы понять, что вызывает ошибку, а не то, как это должно быть сделано. Я очень хорошо знаю, как это должно быть сделано. Это удивительный вопрос компилятора С++. Не то, как это должно быть сделано или что вы не понимаете. Я ясно сказал: я не понимаю, почему изменение порядка двух объявлений вызывает ошибку компилятора?

zdenko.s 13.02.2023 18:27
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
8
66
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Повторное объявление функции не требуется для повторения ее спецификации связи. По языковой привязке от cppreference:

Функция может быть повторно объявлена ​​без спецификации привязки после того, как она была объявлена ​​со спецификацией языка, второе объявление будет повторно использовать первую привязку к языку. Обратное неверно: если первое объявление не имеет языковой привязки, предполагается "C++", а повторное объявление с другим языком является ошибкой.

В первом фрагменте вы объявляете функцию с привязкой "C", а затем повторно объявляете ее без явной привязки. Это нормально; исходная связь предполагается. Однако во втором фрагменте вы объявляете функцию с (неявной) связью "C++", а затем пытаетесь повторно объявить ее с помощью связи "C" — это конфликт, отсюда и ошибка.

Это именно то, что я искал. Часть ссылки на cpp, которая объясняет, почему важен порядок объявления. Ответ в «Противоположное неверно:»

zdenko.s 13.02.2023 18:31

Другие вопросы по теме