reinterpret_cast для void * не работает с указателями на функции

Я хочу переосмыслить приведение указателя функции в переменную void *. Тип указателя на функцию будет иметь тип.Class* (*)(void*)

Ниже приведен пример кода,

class Test
{
    int a;
};

int main()
{
    Test* *p(void **a);
    void *f=reinterpret_cast(p);     
}

Приведенный выше код хорошо работает с компиляторами Visual Studio / x86. Но с ARM-компилятором это дает ошибку компиляции. Дон»не знаю почему.

Ошибка: # 694: reinterpret_cast не может отбрасывать const или другие квалификаторы типа

Я читаю объяснение вПриведение указателя на функцию другого типа

Я был обеспокоен приведенным ниже объяснением.

Приведение между указателями на функции и обычными указателями (например, приведениеvoid (*)(void) кvoid*). Указатели на функции не подходятt обязательно того же размера, что и обычные указатели, поскольку на некоторых архитектурах они могут содержать дополнительную контекстную информацию. Это вероятно будет работать нормально на x86, но помните, что этос неопределенным поведением.

Как сделать такие преобразования изvoid (*)(void*) -> void* эффективно, чтобы по крайней мере он компилируется почти одинаково в большинстве компиляторов?

 MSalters20 авг. 2009 г., 12:11
Обратите внимание, что p на самом деле имеет тип Test ** (void **) и является функцией, а не указателем функции. Поставить пробел в ""Test* * делаетне влияет на разбор.
 Steve Jessop20 авг. 2009 г., 11:49
Вы должны хотя бы заявить, чтоsizeof (void*) >= sizeof (Test**(*)(void**)), Если это утверждение не удается, то, очевидно, естьнет способа сохранить указатель на функцию вvoid*, Если утверждение не терпит неудачу, оно все еще неничего не гарантирую, но по крайней мереВозможно, актерский состав мог бы работать.

Ответы на вопрос(5)

что вы не можете делать это (строго говоря, приведение кvoid* что-нибудь с помощьюreinterpret_cast также не разрешено - но безмолвно допущено компиляторами.static_cast предназначен для использования здесь).

Я обычно делаю следующее, что делает каламбур, и это рекомендуемый способ сделать это, согласно man-страницеdlopen (о том, что делать обратное - кастингот void* в указатель на функцию). Взяв адрес указателя функции, вы получите указатель на данные: указатель на указатель на функцию. Это позволит вам привести его кvoid*, Притворяетсяуказывает наvoid* (вместо указателя на функцию), а затем читает его.

Test* (*pF)(void **a);
void *p = *(void**)(void*)&pF;

Посредник приведен кvoid* делает это эквивалентным использованию двухstatic_casts внутренне, и заставляет GCC молчать об предупреждении о типе каламбура. При использовании приведения в стиле C ++ это выглядит как комбинация двухstatic_cast

void *p = *static_cast<void**>(static_cast<void*>(&pF));
</void*></void**>

Я обнаружил, что, используя эту технику, GCC автоматически замечает, когда левый и правый типы различаются по размеру, и выдает предупреждение в этом случае. Излишне говорить, что, как и во всех методах, которые пытаются обойти это ограничение, это неопределенное поведение.

Если у вас есть функция, и вы хотитеvoid* указывая на это, вы можете сделать все это в одну строку, но этоНемного обременительно по синтаксису. Вот как это можно сделать, но я неЯ рекомендую его, если у вас есть проблемы с его чтением - вы можете использовать его внутри макроса

// using the function declaration you provided
Test** pF(void **a); 
void *p = *(void**)(void *) &(Test** (* const&)(void **a))&pF;

Хитрость для того, чтобы начать иметь возможность делать тип, но состоит в том, чтобы преобразовать временный указатель функции в ссылку на lvalue на const, которую вы можете взять по адресу, и затем продолжить, как описано выше.

Использование явного стиля C ++static_cast бросает, это выглядит намного сложнее, потому что вы должны принять во внимание постоянство. Приведение в стиле C автоматически с этим справляется. Повеселись!

int main() {
    Test** pF(void **a);
    void *p = *static_cast<void* const*="">(
      static_cast<void const*="">(
        &static_cast<test** (*="" const&)(void="" **a)="">(&pF)));
}
</test**></void></void*>
 snogglethorpe22 дек. 2011 г., 08:21
Спасибо за это - код заставляет мои глазные яблоки ползать, но, похоже, он работает правильно и избегает предупреждений / ошибок даже при максимальных уровнях предупреждений в gcc и clang.

добавить постоянствопреобразовать указатель в целочисленный тип, достаточно большой, чтобы удерживать его и обратнопреобразовать указатель на функцию в указатель на функцию другого типапреобразовать указатель на объект в указатель на объект другого типапреобразовать указатель на функцию-член в указатель на функцию-член другого типапреобразовать указатель на объект-член в указатель на объект-член другого типаа такжеreinterpret_cast(x) эквивалентно*reinterpret_cast(&x) (используя встроенный& а также*) всякий раз, когда второй актерский состав возможен с использованием вышеуказанных правил.

(См. Раздел 5.2.10 стандарта)

Это, в частности, означает, что приведение из указателя на функциюvoid * не возможно, но вы можете привести его к.void(*)()

РЕДАКТИРОВАТЬ (2017): Ответ выше верен только для C ++ 03. В C ++ 11 - C ++ 17 это определяется реализацией, если преобразования между указателями на функции иvoid * разрешены. Это обычно имеет место в POSIX-совместимых системах, потому чтоdlsym() объявлено о возвращенииvoid *и клиенты должныreinterpret_cast это правильный тип указателя функции.

Увидетьcppreference.com для полного списка разрешенных преобразований.

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

class Test {
  int a;
};

int main()
{
  Test* *p(void **a);
  void (*f)()=reinterpret_cast<void (*)()="">(p);
}
</void>

Это действительно сделать черезreinterpret_cast (5.2.10 / 6):

Указатель на функцию может быть явно преобразован в указатель на функцию другого типа. Эффект вызова функции через указатель на тип функции (8.3.5), который отличается от типа, используемого в определении функции, не определен. За исключением того, что преобразование rvalue типа "указатель на Т1 " к типу "указатель на Т2 " (где T1 и T2 являются типами функций) и обратно в исходный тип возвращает исходное значение указателя, результат такого преобразования указателя не определен.

Решение Вопроса

reinterpret_cast Можно'может использоваться для приведения указателя на функцию кvoid*, Хотя есть несколько дополнительных вещей, которые C-бросок может делать, которые неДопускается сочетание статических, реинтерпретированных и константных приведений, что преобразование не является одним из них.

В C актерский состав разрешен, но этоповедение нет определен (то есть даже туда и обратно нет гарантированно работать).

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

я играл с несколькими компиляторамиве здесь:

никто не мешает касту C, даже в режиме наибольшего соответствия. Некоторые выдают предупреждение в зависимости от уровня предупреждения и соответствия, другие не дают предупреждения, что бы я ни пытался.reinterpret_cast был ошибкой с некоторыми компиляторами даже на более расслабленном уровне, в то время как другие принимали его во всех случаях, даже не предупреждая.

В последнем доступном проекте для C ++ 0Xreinterpret_cast между указателями функций и указателями объектов поддерживается условно.

Обратите внимание, что, если это имеет смысл или нет, будет зависеть от цели больше, чем от компилятора: переносимый компилятор, такой как gcc, будет иметь поведение, навязанное целевой архитектурой и, возможно, ABI.

Как другие сделали замечание,

Test* *p(void **a);

определяет функцию, а не указатель на функцию. Но функция указатель на функцию неявного преобразования сделана для аргумента reinterpret_cast, так что get для reinterpret_cast является a.Test** (*p)(void** a)

Благодаря Ричарду, который заставляет меня вернуться к этой проблеме более подробно (для записи, я ошибся, полагая, что указатель на функцию для указателя на объект был одним из случаев, когда приведение C допускало что-то, не санкционированное C ++ комбинациями приведений).

 Richard Corden20 авг. 2009 г., 11:50
(Почти -1) я неНе думаю, что это правильно, можете ли вы дать ссылку на это? Это'Я понимаю, что приведение в стиле C определяется в терминах новых стилей приведений. Поэтому, если этоНевозможно сделать это с помощью reinterpret_cast, тогда это невозможно и для приведения в стиле C.
 vprajan20 авг. 2009 г., 11:33
С ролями работал отлично. Благодарю. :)

Test* *p(void **a); быть?Test* (*p)(void **a)

Может в этом твоя проблема?

 vprajan20 авг. 2009 г., 14:07
Тестовое задание*р (недействительныйа) также разрешает тип Test * () (Недействительный) .. так что я думаю, что оба представления являются действительными. Я уверен в этом, потому что я тоже так пробовал ..

Ваш ответ на вопрос