Imagine the following situation where I have a noexcept
C++ free function that is passed as function pointer to another function with C linkage:
extern "C" {
void some_fun(void(*)());
}
void my_fun() noexcept { /* do stuff */; }
int main()
{
some_fun(my_fun);
}
Is that correct and/or allowed? What happens in this case? What are the semantics here considering that since C++17 noexcept
belongs to the type of a function?
In addition, and to my surprise, this even compiles (with both gcc and clang):
extern "C" {
void some_fun(void(*)() noexcept);
}
void my_fun() noexcept { /* do stuff */; }
int main()
{
some_fun(my_fun);
}
Does it even make sense that a function pointer in the signature of a C function allows the qualifier noexcept
in it?
Is that correct and/or allowed? What happens in this case? What are the semantics here considering that since C++17 noexcept belongs to the type of a function?
It is correct and allowed. What happens is that there is an implicit conversion sequence from void(*)() noexcept
to void(*)()
(but not the other way around). This conversion will convert the function pointer to the expected type without noexcept
. The function can be called through the pointer without noexcept
without any restrictions.
In addition, and to my surprise, this even compiles (with both gcc and clang):
There is no requirement that types used in a function declaration with "C"
linkage must be C types. From the point of view of C++ there is no difference to normal behavior, except that the name of the function ignores namespaces and can't be overloaded (i.e. from the typical implementation point-of-view name mangling is disable).
However, what such a declaration means for actual interop with C code, is implementation-defined. Of course you wouldn't be able to declare or define the function with the same signature in C. If you changed the signature for the C part of the program, you should really be sure about the specific way in which your compiler compiles the code to make sure that there is well-defined behavior.
As the other answer by @Artyer points out, according to the standard, the language linkage of a function is part of its type and the function parameter in the function declared with "C"
linkage inherits this language linkage. my_fun
is not a function with "C"
linkage and therefore can't be passed as a pointer to a function with "C"
linkage. I suppose this is intended to allow different calling conventions between C and C++. In all cases I am aware of compilers ignore this part of the standard and consider the language linkage not part of the type.