Проверка наличия функции у C-linkage во время компиляции [неразрешимо] - PullRequest
8 голосов
/ 29 мая 2010

Есть ли способ проверить, объявлена ​​ли данная функция с помощью C-linkage (то есть с extern "C") во время компиляции?

Я занимаюсь разработкой системы плагинов. Каждый плагин может предоставлять заводские функции для кода загрузки плагинов. Однако это должно быть сделано через имя (и последующее использование GetProcAddress или dlsym). Это требует, чтобы функции были объявлены с помощью C-linkage, чтобы предотвратить искажение имен. Было бы хорошо иметь возможность выдать ошибку компилятора, если ссылка на функцию объявлена ​​с помощью C ++ - linkage (в отличие от обнаружения во время выполнения, когда функция с таким именем не существует).

Вот упрощенный пример того, что я имею в виду:

extern "C" void my_func()
{
}

void my_other_func()
{
}

// Replace this struct with one that actually works
template<typename T>
struct is_c_linkage
{
    static const bool value = true;
};

template<typename T>
void assertCLinkage(T *func)
{
    static_assert(is_c_linkage<T>::value, "Supplied function does not have C-linkage");
}

int main()
{
    assertCLinkage(my_func); // Should compile
    assertCLinkage(my_other_func); // Should NOT compile
}

Есть ли возможная реализация is_c_linkage, которая выдаст ошибку компилятора для второй функции, но не для первой? Я не уверен, что это возможно (хотя это может существовать как расширение компилятора, о котором я все еще хотел бы знать). Спасибо.

Ответы [ 2 ]

2 голосов
/ 30 мая 2010

Я согласен с Джонатаном Леффлером, что это, вероятно, невозможно стандартным способом. Возможно, это будет возможно в некоторой степени, в зависимости от компилятора и даже версии компилятора, но вам придется поэкспериментировать, чтобы определить возможные подходы и принять тот факт, что поведение компилятора было непреднамеренным и могло быть «исправлено» в более поздних версиях. 1001 *

Например, в g++ версии 4.4.4 в Debian Squeeze вы можете вызвать ошибку компилятора для функций, которые не stdcall, при таком подходе:

void my_func() __attribute__((stdcall));
void my_func() { }

void my_other_func() { }

template <typename ret_, typename... args_>
struct stdcall_fun_t
{
    typedef ret_ (*type)(args_...) __attribute__((stdcall));
};

int main()
{
    stdcall_fun_t<void>::type pFn(&my_func),
        pFn2(&my_other_func);
}

g++ -std=c++0x не может скомпилировать этот код, потому что:

SO2936360.cpp: 17: ошибка: недопустимое преобразование из «void () ()» в «void () ()»

Строка 17 - это объявление pFn2. Если я избавлюсь от этого объявления, то компиляция завершится успешно.

К сожалению, эта техника не работает с cdecl.

0 голосов
/ 30 мая 2010

Для Unix / Linux, как насчет анализа полученного двоичного файла с помощью 'nm' и поиска имен символов? Я полагаю, это не то, что вы имели в виду, но все же это время компиляции.

...