C ++ - 17: приведение указателя функции к функции с другим типом указателя аргумента - PullRequest
1 голос
/ 11 марта 2020

У меня есть устаревший C -API, который обеспечивает обратные вызовы для асинхронных операций. Так как эта библиотека требует много флагов компилятора, полна макросов и заголовок генерирует тонны предупреждений при включении, я решил создать оболочку для этой библиотеки, которая инкапсулирует проприетарную C -библиотеку.

Но так как это Библиотека является асинхронной, она предоставляет функции обратного вызова. Проблема в том, что для обратного вызова требуется указатель на структуру (X_leg). Но так как эта структура является частью старого API, и я не хочу включать структуру, я решил создать структуру с тем же макетом X_wrp. В main () я гарантирую, что размер обеих структур равен.

Мой вопрос сейчас: Безопасно ли reinterpret_cast указатель функции-оболочки типа func_wrp на указатель устаревшей функции с типом func_leg? Или это неопределенное поведение в C ++ 17?

У меня есть следующий минимальный рабочий пример:

#include <iostream>
#include <cstdint>

//begin of wrapper decls
struct X_wrp {
    std::uint32_t member;
};

using func_wrp = void (*)(const X_wrp* arg);

void caller_wrp(func_wrp func);
//end of wrapper decls

//Legacy C-Code
typedef struct {
    std::uint32_t member;
} X_leg;

typedef void (*func_leg)(const X_leg* arg);

void caller_leg(func_leg func) {
    static X_leg inst{10};
    func(&inst);
}
//End of Legacy C-Code

void callback(const X_wrp* arg) {
    std::cout << arg->member << std::endl;
}

int main() {
    static_assert(sizeof(X_leg)==sizeof(X_wrp));//ensures that there is no oops
    caller_wrp(callback);
    return EXIT_SUCCESS;
}

//begin of wrapper implementations
void caller_wrp(func_wrp func) {
    caller_leg(reinterpret_cast<func_leg>(func)); //is this cast safe?

}
//end of wrapper implementations

1 Ответ

1 голос
/ 11 марта 2020

Нет, это небезопасно и явно вызывается как неопределенное поведение в [expr.call] / 6

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

Это также подтверждено в документации reinterpret_cast о преобразованиях указателей на функции [expr.reinterpret.cast] / 6

Указатель функции может быть явно преобразован в указатель функции другого типа. [Примечание: эффект вызова функции через указатель на тип функции ([dcl.fct]), который отличается от типа, используемого в определении функции, не определен ([expr.call]). - примечание конца] За исключением того, что преобразование prvalue типа «указатель на T1» в тип «указатель на T2» (где T1 и T2 являются типами функций) и обратно к его исходному типу дает исходное значение указателя, результат такого преобразование указателя не указано. [Примечание: Смотрите также [conv.ptr] для более подробной информации о преобразованиях указателя. - Конечная нота]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...