Подтвердить что ты не робот

Как проверить, существует ли функция в C/С++

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

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

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

4b9b3361

Ответ 1

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

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

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

Если кодирование в Linux с помощью GCC, вы также можете использовать атрибут weak в объявлениях. Затем компоновщик установил undefined слабые символы в значение null.

добавлений

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

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

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

Ответ 2

Когда вы объявляете "сумму", вы можете объявить ее как:

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

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

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

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

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

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

....

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

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

Ответ 3

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

 //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"]();
 }

Ответ 4

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

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

Ответ 5

С помощью 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".

Ответ 6

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

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

Ответ 7

Таким образом, если вы используете С++ 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 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);

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

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

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

Ответ 8

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

Этот пример и комментарий от Внутренняя история общих библиотек и динамическая загрузка:

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

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