Почему Вам нужен “экстерн C” для обратных вызовов C++ к функциям C?

Я нахожу такие примеры в коде Повышения.

namespace boost {
   namespace {
     extern "C" void *thread_proxy(void *f)
     {
       ....
     }

   } // anonymous
   void thread::thread_start(...)
   {
       ...
       pthread_create(something,0,&thread_proxy,something_else);
       ...
   }
} // boost

Почему Вам на самом деле нужно это extern "C"?

Ясно что thread_proxy функция частная внутренний, и я не ожидаю, что она была бы искажена как "thread_proxy", потому что мне на самом деле не нужен в искаженный вообще.

На самом деле во всем моем коде, который я написал и это работает на многих платформах, я никогда не использовал extern "C" и это работало как есть с нормальными функциями.

Почему extern "C" добавленный?


Моя проблема - это extern "C" функции загрязняют глобальное пространство имен, и они не на самом деле скрыты, как автор ожидает.

Это не дубликат! Я не говорю об искажении и внешней связи. Очевидно в этом коде, что внешняя связь нежелательна!

Ответ: соглашения о вызовах C и функций C++ являются не обязательно тем же, таким образом, необходимо создать один с соглашением о вызовах C. См. 7.5 (p4) стандарта C++.

17
задан Jonathan Leffler 31 May 2016 в 02:20
поделиться

5 ответов

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

Тем не менее, он все равно будет поврежден. (Если бы не extern "C" ) Вот так работает компилятор. Я согласен с тем, что компилятор может сказать: «Это не обязательно должно быть искажено», но в стандарте об этом ничего не говорится. Тем не менее, искажение здесь не играет роли, поскольку мы не пытаемся связать с функцией.

Фактически, во всем моем коде, который я написал и который работает на многих платформах, я никогда не использовал extern «C» , и это работало как есть с обычными функциями.

Запись на разных платформах не имеет ничего общего с extern «C» . Я ожидаю, что весь стандартный код C ++ будет работать на всех платформах, имеющих стандартный компилятор, совместимый с C ++.

extern «C» имеет отношение к взаимодействию с C, библиотекой которого является pthread. Он не только не искажает имя, но и обеспечивает возможность вызова в соответствии с соглашением о вызовах C. Это соглашение о вызовах, которое должно быть гарантировано, и поскольку мы не можем предположить, что работаем на определенном компиляторе, платформе или архитектуре, лучший способ попробовать и сделать это - использовать предоставленные нам функции: extern «С» .

Моя проблема в том, что функции extern «C» загрязняют глобальное пространство имен и на самом деле они не скрыты, как ожидал автор.

В приведенном выше коде нет ничего загрязняющего.Он находится в безымянном пространстве имен и недоступен за пределами единицы перевода.

17
ответ дан 30 November 2019 в 12:43
поделиться

Вопрос верен - хотя функция передается в библиотеку C, эта библиотека C вообще не связывается с кодом C ++. Ему дается только адрес функции, поэтому имя функции его не интересует.

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

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

5
ответ дан 30 November 2019 в 12:43
поделиться

Он используется для того, чтобы функция использовала то, что компилятор понимает согласно соглашению о вызовах C, избегая при этом специфичных для компилятора ключевых слов, таких как __ cdecl .


Вот и все. Это не имеет абсолютно ничего общего с изменением имен, пространствами имен или любыми другими странными ответами здесь (как вы уже знали, когда спрашивали).

1
ответ дан 30 November 2019 в 12:43
поделиться

Вероятно, потому что вы взаимодействуете с простой библиотекой C - pthreads.

0
ответ дан 30 November 2019 в 12:43
поделиться

extern "C" не обязательно означает, что подавляется только искажение имен. Фактически, может существовать компилятор, который обрабатывает extern «C» как другое соглашение о вызовах.

Стандарт оставляет это полностью открытым как семантика, определяемая реализацией.

6
ответ дан 30 November 2019 в 12:43
поделиться