C ++: безопасно ли привести указатель на функции? - PullRequest
1 голос
/ 25 декабря 2011

Мне интересно, безопасно ли приводить double (*)(double) к double(*)(...), это будет использоваться для обобщения кода, который может иметь указатели на несколько функций.

До сих пор я хранил все, что будет передаваться функции в векторе, и мне интересно, есть ли способ вызвать функцию (при передаче правильного числа аргументов) в обобщенном код? Я имею в виду что-то такое:

//while initializing
mFunction = sin;
//later in code
double (*generalized)(...) = mFunction;
for(i=0;i<args.size();i++)
    pusharg(args[i]);
call(generalized);

- изменить -

если нет правильного способа сделать это с помощью c ++, можно ли вызвать функцию с помощью ассемблера?

Ответы [ 3 ]

3 голосов
/ 25 декабря 2011

Вы не можете напрямую назначить double(*)(double) для double(*)(...), но вы можете reinterpret_cast его.Приведение явно разрешено в §5.2.10 [expr.reinterpret.cast] / 6, но вызов указателя приведенной функции вызовет неопределенное поведение:

Указатель на функцию может быть явно преобразованным в указатель на функцию другого типа.

Эффект вызова функции через указатель на тип функции, который не совпадает с типом, используемым в определении функции, равен undefined .

За исключением того, что преобразование значения типа «указатель на T1» в тип «указатель на T2» (где T1 и T2 являются типами функций) и обратно в его исходный тип дает оригинальное значение указателя, результат такого преобразования указателя не определен.

Легко понять, почему это приводит к UB - что если мы назовем generalized(1.0, 2.0, 3.0)?Это может повредить стек вызовов.Но хорошо, если вы приведете generalized обратно к double(*)(double) до того, как его вызовете.

1 голос
/ 25 декабря 2011

Да, сам кастинг разрешен.Называть это с неправильной подписью не все же.Обратите внимание, что если вам нужен универсальный указатель на функцию, лучше используйте void (*)(), это похоже на void* для указателей на функции (хотя и без неявного преобразования в него).

Или даже лучше, поскольку вы предоставляете конкретные аргументыиспользуйте std::function и std::bind (если ваш компилятор поддерживает библиотеки C ++ 11) или их эквиваленты Boost.

0 голосов
/ 02 марта 2013

Создание generalized volatile потребует от компилятора соблюдения спецификации ABI.Из-за желания поддерживать необъявленные функции C это безопасно для большинства ABI (включая x86 и x86-32), если не вызывать функцию, которая превышает переменное число аргументов, хотя указатель на функцию с фиксированным числом аргументов.

...