[this question has one SO duplicate I can find, but that answer is plain wrong, see the C code below.]
I understand extern "C"
does not produce C code in the middle of your C++. It is just a linkage directive.
I have a few of these extern "C"
tales to tell, but here is one that bothers me today. This is a completely up-to-date VS2019, and this is the code:
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
// NOTE: in here it is still C++ code,
// extern "C" is a linkage directive
typedef struct Test Test;
struct Test {
/* remove this const and MSVC makes no warning
leave it in and MSVC complains, a lot
GCC or clang could not care less
*/
const
uint32_t x;
} ;
/*
MSVC throws warning C4190: 'make_Test' has C-linkage specified,
but returns UDT 'Test' which is incompatible with C
: see declaration of 'Test'
*/
inline constexpr Test make_Test(uint32_t x_ )
{
return Test{ x_ };
}
#ifdef __cplusplus
}
#endif
int main( void )
{
constexpr auto test_{ make_Test(42) };
return test_.x ;
}
Link to the mandatory GODBOLT: https://godbolt.org/z/ecdz1vqhq
That comment about that const is the gist of my question.
MSVC extern "C" is largely (completely?) undocumented. Thus I am unable to tell if, I am breaking some rules in this undocumented zone. Many claim this is some kind of "not fully implemented" C11 in there.
AFAIK having that const for a C11 (or any other C) struct member type is quite OK. And good old GCC could not care less of course. As visible i that GODBOLT on-line.
Is this just a bug in VS2019, or is it me who made a bug?
Update
Even if I move the implementation of make_Test
into a separate C file, and explicitly compile it as C, this Warning will stay the same.
About that 'answer' from the same question from before. C can have const struct data members, and of course, C structs can be list initialized when made. See the code below:
// gcc prog.c -Wall -Wextra -std=gnu11 "-Wno-unused-parameter" "-Wno-unused-variable"
#include <stdlib.h>
typedef struct Test { const long x; } Test;
static struct Test make_Test(long x)
{
struct Test test_ = { x } ;
return test_;
}
int main(const int argc, const char * argv[])
{
struct Test test_ = make_Test(42) ;
return 42;
}