0

This short example comes from a real problem I had when accidently putting an old version of a header file into my include path. I wonder why the following code produces no warning or error with neither gcc nor visual studio:

main.cpp:

#include <stdio.h>

struct B {
    int x;
};

extern void callB(B& b);

int main() {
    B b;
    b.x = 2;
    int sideEffect = 1;
    callB(b);
    printf("x=%d\n", b.x);
    printf("sideEffect=%d\n", sideEffect);
    return 0;
}

call.cpp:

#include <stdio.h>

struct B {
    int y;
    int x;
};

void callB(B& b) {
    printf("x=%d y=%d\n", b.x, b.y);
    b.x = 3;
    b.y = 4;
    printf("x=%d y=%d\n", b.x, b.y);
}

The output of this short program is:

x=1 y=2
x=3 y=4
x=4
sideEffect=3

So I have two conflicting definitions of the struct B, and to make things worse, the extra member y is put before x. Thus in call.cpp the value of y is that of x in main.cpp So I can completely understand why the output is as it is, but since this behaviour would irritate both the maintainer of main.cpp and the other maintainer of call.cpp, I wonder why there is no check in the compiler or linker for this?

BTW: if you look into this with a debugger things become even more obscure, as the debugger assumes one of both definitions and may lead you into even more confusion (especially when the structs are more complex than here).

Yksisarvinen
  • 18,008
  • 2
  • 24
  • 52
kameamea
  • 1
  • 3
  • 1
    your code can either be C++ or C, and that will change details of how it works. You'll have to settle on one of the two tags. To me, your code looks like C, but your file names claim C++, so what is it? – Marcus Müller Jun 08 '21 at 09:56
  • 2
    Compiler has no means of checking that (it compiles one translation unit at a time with no memory in between) and linker doesn't really care about classes, it gets some files with gaps for functions and fills those in. Standard calls this "One Definition Rule violation - no diagnostic required". – Yksisarvinen Jun 08 '21 at 09:58
  • @MarcusMüller What exactly would change? – Peter - Reinstate Monica Jun 08 '21 at 09:59
  • @Peter-ReinstateMonica if we have two diverging types, in C++ that would simply lead to an overload of `callB`, and I'd have to explain that, too :) – Marcus Müller Jun 08 '21 at 10:00
  • @MarcusMüller What makes you think that there would be an overload? – Peter - Reinstate Monica Jun 08 '21 at 10:01
  • The formal term is "ODR violation". Look it up. – Aykhan Hagverdili Jun 08 '21 at 10:06
  • @MarcusMüller What I want to get at is that C++ has inherited this exact problem from C because it re-uses the linker, and hence the translation unit and object file paradigm, including the object file format (as opposed to languages like C# or Java). The problem is *exactly identical* in C and C++. – Peter - Reinstate Monica Jun 08 '21 at 10:07
  • @Peter-ReinstateMonica I got into the habit of simply removing one of the tags when I see double tagging. I mean, irrespective of whether the answer applies to both, almost all the time the question really is about only one of them. – 463035818_is_not_an_ai Jun 08 '21 at 10:44
  • The problem is precisely here: _'So I have two conflicting definitions of the struct B,'_ And header files were devised exactly to solve this problem. Just use them (or ask both 'maintainers' to learn using them.) – CiaPan Jun 08 '21 at 11:04
  • @CiaPan in my original problem the structs were in header files (as mentioned in the first sentence). But there existed an outdated version of the same header file in the include path leading to hard to debug problems, which I wanted to show. – kameamea Jun 08 '21 at 16:32

0 Answers0