внешние функции C в скомпилированном объектном коде

Среда — Microsoft Visual C++ 2015 и Windows 7.

Есть ли что-то особенное в inline extern "C" функциях, определенных в заголовке? Я потребляю SDK, в котором один из заголовков содержит такого зверя. В моем приложении у меня есть одинокая TU (единица перевода), единственной задачей которой является включение вышеупомянутого заголовка. Это все. Ничего другого в нем нет. Если я покопаюсь в сгенерированном объектном файле, я увижу, что функция extern "C" загружается. Это вызывает у меня некоторые нежелательные побочные эффекты (я пока не упомяну их, так как это может просто отвлечь от основной проблемы).

Почему это произошло? В клиентском коде нет ничего (помните, что мой единственный TU пуст, за исключением точки входа main() и этого заголовка), что вызывает это.

ОБНОВЛЕНИЕ с небольшим фрагментом, который мог бы лучше объяснить, с чем я столкнулся:

Вот что происходит на самом деле:

FooObj.h

FooObj::FooObj() { }

FooObj::~FooObj() { CallIntoAnotherC_API(); }

SDKHeader.h

#include <FooObj.h>

extern "C" inline void SomeFunc(void* user_data)
{   
    A* obj = static_cast<A*>(user_data);
    obj->CallAnotherFunc(FooObj(33));
}

Мой файл.cpp

#include "SDKHeader.h"

int main() { return 0; }

Компиляция MyFile.cpp в исполняемый файл завершается сбоем, поскольку компоновщик жалуется, что CallIntoAnotherC_API является неразрешенным внешним.


person ForeverLearning    schedule 29.05.2016    source источник
comment
ТУ? объясните пожалуйста.   -  person Henno Brandsma    schedule 29.05.2016
comment
Имма извини, я тебя не понял. Вы не можете понять, что за inline extern "C"?   -  person Шах    schedule 29.05.2016
comment
@HennoBrandsma: Мое предположение: TU = единица перевода.   -  person Martin R    schedule 29.05.2016
comment
ТУ - единица перевода? Правильно? Я думаю, что это был вопрос других комментаторов, и это не был прямой вопрос ????   -  person Dilettant    schedule 29.05.2016
comment
Есть ли что-то особенное в inline extern "C" функциях, определенных в заголовке? Одним словом, нет. Почему это произошло? Что именно? Неуказанные нежелательные побочные эффекты?   -  person n. 1.8e9-where's-my-share m.    schedule 29.05.2016
comment
@n.m.Я пытаюсь понять, почему ссылки на эту функцию отображаются в скомпилированном объектном файле, когда файл CPP, который включает этот заголовок, не содержит ссылок на что-либо в этом заголовке. Я что-то упускаю.   -  person ForeverLearning    schedule 29.05.2016
comment
Посмотрите внимательно на Является ли inline без static или extern когда-либо полезным в C99. Он охватывает проблему с точки зрения системы C. См. также внешний встроенный, который может быть еще более уместным. По сути, в C один исходный файл может содержать extern inline …function definition…, и этот файл будет содержать не встроенную функцию для встроенной функции.   -  person Jonathan Leffler    schedule 29.05.2016
comment
@JonathanLeffler Спасибо за ссылки. Я прочитаю их сейчас. Я также обновил свой пост, чтобы лучше объяснить, с чем я сталкиваюсь.   -  person ForeverLearning    schedule 29.05.2016
comment
Глядя на дополнительную информацию, бит extern "C" может что-то изменить. Он может просто создать фактическую функцию со связью в стиле C (это означает, что имя не "искажено", чтобы обеспечить вам безопасную для типов связь, как это обычно делает C++), которую можно использовать там, где функция inline не может быть встроена. Но почему это в файле, содержащем только int main() { return 0; }, более загадочно. Непонятно (мне), какие глобальные переменные связываются/инициализируются до запуска main() или уничтожаются после его завершения.   -  person Jonathan Leffler    schedule 29.05.2016
comment
@JonathanLeffler Но почему это в файле, содержащем только int main() { return 0; } более загадочен.: Меня это тоже беспокоит. Возвращаясь к вашему последнему замечанию, вы имели в виду, что должен существовать какой-то невидимый фрагмент кода, который вызывает SomeFunc явно для возникновения этой ситуации?   -  person ForeverLearning    schedule 29.05.2016
comment
В FooObj.h должен быть еще какой-то код — либо напрямую, либо включенный. Наличие встроенных определений конструктора и деструктора не будет работать, если не будет определения класса, с которым может работать компилятор. В определении класса могут быть некоторые детали, которые объясняют происходящее, или какой-то другой код в заголовке, который это объясняет. Хорошо создать MCVE (минимально воспроизводимый пример). Я боюсь, что вы немного слишком минималистичны в (первом обновлении) вопроса, отказавшись от «полных» и «поддающихся проверке» аспектов MCVE.   -  person Jonathan Leffler    schedule 29.05.2016
comment
@JonathanLeffler Я опубликовал ответ, и он, кажется, объясняет ситуацию, но я пока не могу его понять!   -  person ForeverLearning    schedule 29.05.2016
comment
действительно ли реализация CallIntoAnotherC_API() предоставляется компоновщику?   -  person M.M    schedule 30.05.2016
comment
Я бы настоятельно рекомендовал НЕ использовать inline в заголовке, который будет использоваться совместно между C и C++, потому что он имеет разную семантику в каждом из C++, ISO C и GNU C. (не знаю, что с ним делает компилятор C MSVC)   -  person M.M    schedule 30.05.2016
comment
@MM Я выделил еще один поток, чтобы еще больше изолировать проблему. .   -  person ForeverLearning    schedule 30.05.2016


Ответы (1)


Джонатан Леффлер! Большое спасибо за то, что указали мне правильное направление. Я узнал, в чем проблема, и это очень странно, если не сказать больше. Во фрагменте SDKHeader.h, который я разместил выше, есть постороннее объявление SomeFunc, например:

#include <FooObj.h>

// I don't know why this declaration exists but its presence is
// causing the compiler to include SomeFunc and everything it references
// in the object file causing eventual linker errors! Also notice that
// this declaration even misses the "inline" keyword.
extern "C" void SomeFunc(void* user_data);

extern "C" inline void SomeFunc(void* user_data)
{   
    A* obj = static_cast<A*>(user_data);
    obj->CallAnotherFunc(FooObj(33));
}

Удаление этого лишнего объявления избавляет от ошибок компоновщика, а также предотвращает появление фиктивного символа в объектном файле.

person ForeverLearning    schedule 29.05.2016
comment
Чтобы избежать изменения заголовка SDK, что произойдет, если вы предварительно объявите эту функцию так, как вы хотите, прежде чем #include заголовок? Например, extern "C" inline void SomeFunc(void* user_data); или даже inline void SomeFunc(void* user_data);. Возможно, это убедит компилятор использовать версию функции inline и игнорировать все вводящие в заблуждение версии extern, которые идут после нее в файле #include? - person Malvineous; 30.05.2016