Законен ли этот код?
extern "C" typedef void (ft_blah_c)();
/*extern "C++"*/ typedef void (ft_blah_cpp)();
extern "C" void fn_blah_c() {}
/*extern "C++"*/ void fn_blah_cpp() {}
ft_blah_c *g_Blah_c = fn_blah_cpp; // <--- ?
ft_blah_cpp *g_Blah_cpp = fn_blah_c; // <--- ?
У меня есть реальный код с похожими заданиями, он компилируется и выполняется без проблем (MSVC 2010).
В общем, это не должно работать. Проблема в том, что когда вы звоните fn_blah_c
или же fn_blah_cpp
прямо компилятор знает использовать функцию и соглашения о вызовах, но если вы сохраните их в указателе функции, компилятор видит только этот указатель и может использовать только тип указателя функции, чтобы определить, как передавать аргументы и возвращаемые типы.
Если соглашение о вызовах для C и C ++ одинаково в вашей среде, то оно может работать (и, возможно, именно поэтому ваш компилятор это разрешает), но это не так в общем случае, и назначение должно завершиться неудачей.
Нет, это не законно; преобразование между типами функций не может быть неявным.
Разрешается явно приводить между типами функций:
ft_blah_c *g_Blah_c = reinterpret_cast<ft_blah_c>(fn_blah_cpp);
ft_blah_cpp *g_Blah_cpp = reinterpret_cast<ft_blah_cpp>(fn_blah_c);
Однако на самом деле вызов функции через указатель на функцию другого типа — неопределенное поведение. Вы должны преобразовать обратно в исходный тип перед вызовом функции.
Основная причина этого, выходящая за рамки стандарта, заключается в том, что машинные инструкции для вызова функции могут различаться в зависимости от языковой связи функции. Это называется «Соглашения о вызовах» и включает в себя множество деталей, таких как соглашения о передаче аргументов и возвращаемых значений, пролог функции и эпилог и т. д.
Например, функция со связью языка C может ожидать нахождения своих аргументов в стеке, в то время как функция со связью языка C ++ может ожидать передачи аргументов в регистрах. Если вызывающий код не знает правильную связь, он поместит данные аргумента в одно место, а функция будет искать в другом и только читать мусор, поэтому не сможет работать правильно.