3

In the first compilation unit:

/* From .h file */

struct my_struct {
    int foo;
    long bar;
};

void my_struct_init(struct my_struct*);
int my_struct_get_int(struct my_struct*);
long my_struct_get_long(struct my_struct*);

/* From .c file */

void my_struct_init(struct my_struct* o) {
    o->foo = 0;
    o->bar = 0L;
}

int my_struct_get_int(struct my_struct* o) {
    return o->foo;
}

long my_struct_get_long(struct my_struct* o) {
    return o->bar;
}

In the second compilation unit:

/* From .h file */

struct my_struct {
    /* Named differently */
    int foo_different;
    long bar_different;
};

void my_struct_init(struct my_struct*);
int my_struct_get_int(struct my_struct*);
long my_struct_get_long(struct my_struct*);

/* From .c file */

int main(void) {
    struct my_struct o;
    my_struct_init(&o);
    if (o.foo_different != 0 || o.bar_different != 0L) {
        /* (Just assume EXIT_FAILURE is 1) */
        return 1;
    }
    o.foo_different = 1;
    o.bar_different = 2L;
    if (my_struct_get_int(&o) != 1 || my_struct_get_long(&o) != 2L) {
        return 1;
    }
    return 0;
}

Although the two structs have the same name and the members have the same types and order, the members have different names.

Does that mean that the above is not defined? Or will this always succeed?

(For context, I am using this to prefix members with "_my_type_private_" if a header file is included normally, but kept the same if it is included from an internal implementation file, so that the type is not incomplete but it is harder to modify the struct accidentally)

EDIT: the question is not a duplicate of that question but it does provide the correct answer:

Moreover, two structure, union, or enumerated types declared in separate translation units are compatible if [for each pair of member declarations] one member of the pair is declared with a name, the other is declared with the same name

So they are not compatible types.

Artyer
  • 31,034
  • 3
  • 47
  • 75
  • Have you tried actually doing it? I suspect if you try to link the two units, you'll get a linker error about duplicate symbol. – Aleks G Jan 23 '19 at 15:20
  • @AleksG Yes, it works with gcc and clang with no linker error. – Artyer Jan 23 '19 at 15:21
  • @GovindParmar: No, it is not. – Eric Postpischil Jan 23 '19 at 15:25
  • 1
    @EricPostpischil The question itself may not be a duplicate but the answer OP is looking for (do tag and member names affect compatibility?) is discussed in the accepted answer for that question – Govind Parmar Jan 23 '19 at 15:37
  • @GovindParmar: A question is a duplicate if it duplicates another question. If it does not duplicate another question, it is not a duplicate. The fact that an answer to a different question provides information relevant to a question does not make a question a duplicate. When somebody else is looking, in the future, for information on Question A, they will not know to look for different Question B. They will search for Question A and might not find or might overlook closed questions. They will not be served by the fact that some different question contains an answer. – Eric Postpischil Jan 23 '19 at 15:42
  • @EricPostpischil We can discuss this further on [Meta](https://meta.stackoverflow.com/questions/379293/closing-as-a-duplicate-based-on-answer-content) – Govind Parmar Jan 23 '19 at 16:12

1 Answers1

4

C 2018 6.2.7 1 specifies the conditions for two structure types declared in separate translation units to be compatible (emphasis added):

… Moreover, two structure, union, or enumerated types declared in separate translation units are compatible if their tags and members satisfy the following requirements: If one is declared with a tag, the other shall be declared with the same tag. If both are completed anywhere within their respective translation units, then the following additional requirements apply: there shall be a one-to-one correspondence between their members such that each pair of corresponding members are declared with compatible types; if one member of the pair is declared with an alignment specifier, the other is declared with an equivalent alignment specifier; and if one member of the pair is declared with a name, the other is declared with the same name

Since struct my_struct is declared with different member names in the different translation units, the struct my_struct in one translation unit is not compatible with the struct my_struct in another translation unit.

This causes the my_struct_init and other functions declared in one translation unit not to be compatible with the my_struct_init and other functions declared and defined in the other translation unit.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312