Jason Smith
8 posts
Alternative C/C++ type definitions
Edited by Jason Smith on Reason: Initial post
I was messing around and expecting the following to blow up when I tried to compile it but to my shock it totally works. Can someone please explain to me how/why the following works.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 // foo.h #ifndef FOO_H #define FOO_H #ifdef __cplusplus #include extern "C" { #endif typedef struct foo { float x; float y; float z; #ifdef __cplusplus float w; inline foo operator+(const foo& addend) { foo result = { x + addend.x, y + addend.y, z + addend.z, w + addend.w }; return result; } #endif }foo; #ifdef __cplusplus } // End C linkage inline std::ostream& operator<<(std::ostream &os, const foo &inst) { os << inst.x << ' ' << inst.y << ' ' << inst.z << ' ' << inst.w << '\n'; return os; } #endif #endif // FOO_H //cfoo.c #include "foo.h" extern foo c_foo; foo c_foo = { 3.0f, 3.0f, 3.0f }; // main.cpp #include "foo.h" #include extern "C" foo c_foo; static foo cpp_foo = { 1.0f, 2.0f, 3.0f, 4.0f }; int main(){ foo a = cpp_foo + c_foo; std::cout << c_foo; std::cout << cpp_foo; std::cout << a; float w = a.w; std::cout << w << std::endl; std::getchar(); return 0; } 

This certainly seems like a disaster waiting to happen, especially since sizeof() gives a different value depending on if it is used in a .c or .cpp file. I was expecting a multiple definition error but MSVC, Clang, and G++ all compiled and ran the program just fine. I would like to understand why.
Mārtiņš Možeiko
2202 posts / 1 project
Alternative C/C++ type definitions
Edited by Mārtiņš Možeiko on
ODR rule. If you violate it, you get undefined behavior.

From C++ standard (3.2 One Definition Rule):

No translation unit shall contain more than one definition of any variable, function, class type, enumeration type or template.

[...]

There can be more than one definition of a class type [...] in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements.

Given such an entity named D defined in more than one translation unit, then

— each definition of D shall consist of the same sequence of tokens; and

[...]

If the definitions of D satisfy all these requirements, then the program shall behave as if there were a single definition of D. If the definitions of D do not satisfy these requirements, then the behavior is undefined.

Your definition of foo struct has different sequence of tokens in different translation units. Thus undefined behavior.
Jason Smith
8 posts
Alternative C/C++ type definitions
I also noticed the following on cppreference:

the language linkage is the same (e.g. the include file isn't inside an extern "C" block)

I'm thinking that this also contributes to this being undefined?