2013-08-19 4 views
4

Следующие два значения совпадают, но C99 стандартно оставляет листинг от void * до указателя функции undefined.Функциональный указатель на динамическую библиотеку двумя разными способами

Может кто-нибудь объяснить, как работает второй? Это немного запутанно!

int (*fptr)(int); 
fptr = (int (*)(int))dlsym(handle, "my_function"); 


int (*fptr)(int); 
*(void **) (&fptr) = dlsym(handle, "my_function"); 

ответ

3

На первой строке (второй код вставки) объявляет указатель на функцию (я предполагаю, что вы знаете, что).

Теперь dlsym(3) - это вызов, который возвращает void *.

Так вторая линия также может быть прочитана как:

*((void **) (&fptr)) = dlsym(handle, "function"); 

В противном случае, сказал: вместо отливки результата функции, как int (*)(int), и влияющие на данный результат fptr; он накладывает указатель на fptr (или отправляет адрес fptr: указатель на указатель) как void**. Затем он разыгрывает этот указатель, эффективно давая fptr (то же, что и исходный, но без типа int (*)(int)), который затем получает результат вызова dlsym. Это просто способ «обмануть» компилятор, чтобы не запускать предупреждения/ошибки о несоответствии типов. Также обратите внимание, что даже если выбранный вами синтаксис является вопросом вкуса, вы должны полностью понять, прежде чем использовать его в любой программе, которую вы выпустили.

Я надеюсь, что это помогает;)

+0

Это то же самое, что и вторая строка второго кода кода OP ... –

+0

@OliCharlesworth: No. –

+0

Единственное отличие - дополнительные скобки, и они не имеют никакого эффекта. –

2

Разница такая же, как между:

float f = 3.14; 
int i = (int)f; 

и

float f = 3.14; 
int i = *(int*)&f; 

Первый регулярный бросок значения, которые в некоторых случаях (int < -> float или обратно в 8086 дней рядом с указателем < -> дальний указатель) вызывает некоторые преобразования; и в некоторых случаях (некоторые отбрасывания между указателями функций и регулярными указателями) даже не компилируются.

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

+0

+1. Однако обратите внимание, что POSIX-совместимые системы * должны * поддерживать вторую версию OP в случае 'dlsym()' (см. Раздел «Обоснование» здесь: http://pubs.opengroup.org/onlinepubs/009695399/functions/ dlsym.html). –

+0

@Medinoc спасибо. это действительно помогло. – Soosh

+0

@ Oli Charlesworth поблагодарить вас за внимание. – Soosh

1

Причина вторая версия является законным в следующей части стандарта ISO:

6.3.2.3 Указатели 1 Указатель на недействительной может быть превращена в или из указателя на любой тип объекта. Указатель на любой тип объекта может быть преобразован в указатель на void и обратно; результат равен , сравнивается с исходным указателем.

(**void), а также &fptr являются указателями на объекты (с & fptr является указателем на указатель к функции), так что отлитый в вашем втором выражении явно разрешен вышеуказанное заявление.Ваше первое выражение пытается преобразовать указатель на объект (скорее, указатель на void, который является особым случаем в стандарте) указателю на функцию (который является не объектом), что запрещено стандартом как вы указали.

Смежные вопросы