Search code examples
c++visual-c++structextern

`char * const` field considered "incompatible with C" by MSVC (VS2015)


I have the following code which compiles without warnings in VS2015 (all warnings enabled):

// buffer.h

typedef struct {
    char * const start; // start of the buffer
    char * const end;   // one byte after the end of the buffer
    char * pos;         // current position
} Buffer;

static inline Buffer Buffer_create(char *buffer, int size) {
    Buffer b;

    char ** const startPtr = &((char *)b.start);
    char ** const endPtr = &((char *)b.end);

    *startPtr = buffer;
    *endPtr = buffer + size;
    b.pos = buffer;

    return b;
}

Since .start and .end members are const, I am doing the casting thingy to avoid getting compile warnings, and the code indeed compiles without warnings and works without issues.

However, if I want to test this using gtest, and if I want to reference this file from a .cpp file:

// some_file.cpp

extern "C" {
    #include "buffer.h"
}

I get the the C4190 warning from Visual Studio, described as:

'Buffer_create' has C-linkage specified, but returns UDT 'Buffer' which is incompatible with C

But the UDT is clearly "compatible with C", since I can build it without warnings until I try to reference it from a cpp file.

If I remove const from the struct definition, the warning goes away.

So, it seems like MSVC thinks char * const is not "compatible with C". Am I doing something illegal, or is this a compiler bug?


Solution

  • According to the documentation you linked for warning C4190, it is not supported to have a function which returns a struct by value, called from both C and C++.

    (In the C++ Standard most of the details of language-mixing are given as implementation-defined, and in this case MSVC complies by documenting that this is not supported).

    I also would not recommend having an inline function in a header that is compiled as both C and C++, because the semantics of inline differs between the two languages so it is asking for trouble.

    You will have to make a major design change to avoid this problem, if you want to use Buffer_create from both languages. For example, "return" the result via a pointer out-parameter, and do away with the const struct members.