Как проверить, существует ли функция в C / C ++ - PullRequest
21 голосов
/ 11 января 2012

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

like:
if (function 'sum' exists ) then invoke sum ()

Может быть и другой способ задать вопрос: как определить, определена ли функция во время выполнения, и если да, то вызвать.

Ответы [ 8 ]

12 голосов
/ 11 января 2012

Когда вы объявляете 'sum', вы можете объявить это как:

#define SUM_EXISTS
int sum(std::vector<int>& addMeUp) {
    ...
}

Тогда, когда вы начнете использовать его, вы можете пойти:

#ifdef SUM_EXISTS
int result = sum(x);
...
#endif

Я предполагаю, что вы пришли из языка сценариев, где все делается во время выполнения. Главное, что нужно помнить в C ++, это две фазы:

  • Время компиляции
    • Препроцессор работает
    • код шаблона превращается в реальный исходный код
    • исходный код превращен в машинный код
  • время выполнения
    • машинный код запускается

Так что все #define и тому подобные вещи происходят во время компиляции.

....

Если вы действительно хотите сделать все это во время выполнения ... вас может заинтересовать использование некоторых из продуктов с компонентной архитектурой .

Или, может быть, архитектура типа плагина - это то, что вам нужно.

10 голосов
/ 01 августа 2013

Я подозреваю, что на самом деле постер искал что-то большее по линии проверки / отправки SFINAE. С помощью шаблонов C ++ можно определять функции шаблонов, одна из которых вызывает нужную функцию (если она существует), а другая - ничего не делает (если функция не существует). Затем вы можете сделать первый шаблон зависимым от желаемой функции, так чтобы шаблон был плохо сформирован, когда функция не существует. Это верно, потому что в C ++ ошибка замены шаблона не является ошибкой (SFINAE), поэтому компилятор просто вернется ко второму случаю (который, например, ничего не может сделать).

Смотрите здесь отличный пример: Можно ли написать шаблон для проверки существования функции?

10 голосов
/ 11 января 2012

Хотя другие ответы являются полезными советами (dlsym, указатели функций, ...), вы не можете скомпилировать код C ++, ссылающийся на функцию, которая не существует.Как минимум, функция должна быть объявлена ​​;если это не так, ваш код не будет компилироваться.Если ничего (единица компиляции, некоторый объектный файл, некоторая библиотека) определяет функцию, компоновщик будет жаловаться (если она не слабая, см. Ниже).

Но вы должны действительно объяснить, почемуты спрашиваешь это.Я не могу догадаться, и есть какой-то способ достичь вашей неустановленной цели.

Обратите внимание, что dlsym часто требует функций без искажения имени , то есть объявляется какextern "C".

Если вы кодируете в Linux с помощью GCC, вы также можете использовать атрибут функции *1022* в объявлениях.Затем компоновщик установит неопределенные слабые символы в нуль.

addenda

Если вы получаете имя функции из какого-либо ввода, вы должны знать, что таким способом может вызываться только подмножество функций.(если вы будете вызывать произвольную функцию без заботы, она потерпит крах!), и вам лучше явно создать это подмножество.Затем вы можете использовать std::map или dlsym (с каждой функцией в подмножестве, объявленной extern "C").Обратите внимание, что dlopen с путем NULL дает указатель на основную программу, которую вы должны связать с -rdynamic, чтобы она работала правильно.

Вы действительно хотите вызывать по их имени только подходящим образомопределенное подмножество функций.Например, вы, вероятно, не хотите так называть abort, exit или fork.

NB.Если вы знаете динамически сигнатуру вызываемой функции, вы можете использовать libffi для ее вызова.

10 голосов
/ 11 января 2012

используйте указатели на функции.

 //initialize
 typedef void (*PF)();
 std::map<std::string, PF> defined_functions;
 defined_functions["foo"]=&foo;
 defined_functions["bar"]=&bar;
 //if defined, invoke it
 if(defined_functions.find("foo") != defined_functions.end())
 {
     defined_functions["foo"]();
 }
8 голосов
/ 08 мая 2017

С помощью GCC вы можете:

void func(int argc, char *argv[]) __attribute__((weak)); // weak declaration must always be present

// optional definition:
/*void func(int argc, char *argv[]) { 
    printf("ENCONTRE LA FUNC\n");
    for(int aa = 0; aa < argc; aa++){
        printf("arg %d = %s \n", aa, argv[aa]);
    }
}*/

int main(int argc, char *argv[]) {
    if (func){ 
        func(argc, argv); 
    } else {
        printf("no encontre la func\n");
    }
}

Если вы раскомментируете func, он запустит его, в противном случае будет напечатано «no encontre la func \ n».

4 голосов
/ 11 января 2012

Если вы знаете, в какой библиотеке находится функция, которую вы хотите вызвать, то вы можете использовать dlsym() и dlerror(), чтобы выяснить, существует ли онаи каков указатель на функцию.

Редактировать: Вероятно, я бы на самом деле не использовал этот подход - вместо этого я бы порекомендовал решение Матиу, так как я думаю, что это гораздо лучшая практика.Однако dlsym() не очень хорошо известен, поэтому я подумал, что укажу на это.

2 голосов
/ 30 декабря 2013

Итак, другой способ, если вы используете c ++ 11, это использовать функторы:

Вам нужно будет поместить это в начало вашего файла:

#include <functional>

Тип функтора объявлен в следующем формате:

std::function< return_type (param1_type, param2_type) >

Вы можете добавить переменную, содержащую функтор для суммы, например:

std::function<int(const std::vector<int>&)> sum;

Чтобы упростить задачу, давайтеукоротить тип параметра:

using Numbers = const std::vectorn<int>&;

Тогда вы можете заполнить функтор var любым из:

Лямбда:

sum = [](Numbers x) { return std::accumulate(x.cbegin(), x.cend(), 0); } // std::accumulate comes from #include <numeric>

Указатель функции:

int myFunc(Numbers nums) {
    int result = 0;
    for (int i : nums)
        result += i;
    return result;
}
sum = &myFunc;

Что-то, что создало 'bind':

struct Adder {
    int startNumber = 6;
    int doAdding(Numbers nums) {
        int result = 0;
        for (int i : nums)
            result += i;
        return result;
    }
};
...
Adder myAdder{2}; // Make an adder that starts at two
sum = std::bind(&Adder::doAdding, myAdder);

Тогда, наконец, это можно использовать, это простое утверждение if:

if (sum)
    return sum(x);

InТаким образом, функторы являются новым указателем на функцию, однако они более универсальны.На самом деле может быть встроенным, если компилятор достаточно уверен, но обычно совпадает с указателем на функцию.

В сочетании с std :: bind и lambda они значительно превосходят указатели на функции старого стиля C.

Но помните, что они работают в среде c ++ 11 и выше.(Не в C или C ++ 03).

1 голос
/ 25 ноября 2015

Вы можете использовать #pragma weak для компиляторов, которые его поддерживают (см. слабый символ запись в Википедии).

Этот пример и комментарий взяты из Inside Story on SharedБиблиотеки и динамическая загрузка :

#pragma weak debug
extern void debug(void);
void (*debugfunc)(void) = debug;
int main() {
    printf(“Hello World\n”);
    if (debugfunc) (*debugfunc)();
}

Вы можете использовать слабую прагму, чтобы заставить компоновщик игнорировать неразрешенные символы [..], программа компилируется и связывается независимо от того, работает ли debug ()фактически определяется в любом объектном файле.Когда символ остается неопределенным, компоновщик обычно заменяет его значение на 0. Таким образом, этот метод может быть полезным для программы, чтобы вызвать дополнительный код, который не требует перекомпиляции всего приложения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...