Привести long к указателю на функцию?

У меня есть следующий код:

long fp = ...
void (*ptr)(long, char*, char*) = fp;

Длинный fp является правильным указателем на функцию, который является длинным. Я получаю стандартное предупреждение «создает указатель из int без приведения». Я хочу иметь возможность компилировать с:

-std=iso9899:1990 -pedantic-errors

что превращает это предупреждение в ошибку. Вопрос: каков правильный состав? Я пробовал разные догадки, например:

void (*ptr)(long, char*, char*) = (void)(*)(long, char*, char*) fp;

Но не могу найти подходящего.


person gub    schedule 04.03.2012    source источник
comment
Почему вы хотите это сделать?   -  person Oliver Charlesworth    schedule 04.03.2012
comment
Приведение между целыми числами и указателями функций?   -  person Oliver Charlesworth    schedule 04.03.2012
comment
Если fp является правильным указателем на функцию, почему он хранится в длинном? Может быть, вам следует сосредоточиться на правильном вводе данных, а не пытаться потом придумать кладж.   -  person Mr Lister    schedule 04.03.2012
comment
Я был бы признателен за ответ на вопрос о актерском составе, а не за редизайн. JNI вводит множество грехов, из которых этот наименьший.   -  person gub    schedule 04.03.2012
comment
@MrLister: бывают случаи, когда это не зависит от тебя. В программировании для Windows обычной практикой является передача указателей любого типа внутри параметров wndproc, которые гарантированно будут достаточно большими для этого. Вероятно, OP использует библиотеку, которая делает такие вещи.   -  person Matteo Italia    schedule 04.03.2012
comment
Кроме того, dlsym-call (POSIX) и GetProcAddress (Windows) заставляют вас приводить целые числа к указателям на функции.   -  person scravy    schedule 04.06.2013


Ответы (4)


«Правильный» состав:

void (*ptr)(long, char*, char*) = (void (*)(long, char*, char*))fp;

Очевидно, это можно исправить с помощью подходящего typedef.

Но в любом случае результат этого определяется реализацией. Если можете, избегайте этого и сохраняйте указатель в типе указателя. Следующим лучшим вариантом было бы использовать intptr_t, если он доступен.

person Oliver Charlesworth    schedule 04.03.2012

Вероятно, это что-то вроде:

void (* ptr)(long, char, char *) = (void (*)(long, char, char *))fp;

но я предлагаю использовать typedef и забыть обо всем этом беспорядке:

typedef void (* fnPtr)(long, char, char*);
fnPtr ptr = (fnPtr) fp;
person Matteo Italia    schedule 04.03.2012

Единственный "правильный" способ - вообще не приводить, а копировать бинарное представление:

long fp;
void (*ptr)(long, char*, char*);

memcpy(&ptr, &fp, sizeof ptr);
person Kerrek SB    schedule 04.03.2012
comment
За исключением того, что он катастрофически терпит неудачу, когда sizeof(long) != sizeof(ptr). - person jørgensen; 04.03.2012

Основная проблема здесь в том, что ANSI-C не позволяет этого, несмотря на бесчисленное множество C-API, полагающихся на эту функцию. Таким образом, вы, вероятно, столкнетесь с проблемами при компиляции с помощью -pedantic. Как намекали другие плакаты, вы можете обмануть актерский состав, используя такие вещи, как memcpy() или тип объединения для литья.

Между прочим, POSIX гарантирует, что это сработает, поэтому часть о «результатах, определяемых реализацией» становится намного менее пугающей.

person ComicSansMS    schedule 04.03.2012
comment
C99 явно разрешает это, он просто указывает, что результаты определяются реализацией. - person Oliver Charlesworth; 04.03.2012
comment
Круто, я этого не знал. Я в основном парень на C++, поэтому я больше знаком с C89, который afaik не позволял. - person ComicSansMS; 04.03.2012