Home > Enterprise >  Same struct with different definitions in translation units
Same struct with different definitions in translation units

Time:10-19

0.c

#include <stdio.h>

struct test{
 int a;
};

struct test get(int in);

int main(){
 struct test t = get(1234);
 printf("%d\n",t.a);

 return 0;
}

1.c

struct test{
 char a;    // Note this is char instead of int.
};

struct test get(int in){
  struct test t = {in};
  return t;
}

struct test has two different definitions. One with int and the other with char as its data type.

Is this Undefined Behaviour? C doesn't officially have the one dentition rule like C and this post says multiple definitions are ok? Are different translation units allowed to define structures with the same name?

CodePudding user response:

Is this Undefined Behaviour?

Yes.

and this post says multiple definitions are ok?

Sure, but not when they are used like in between both TUs.

The problem is not even at struct test t = get(1234);, but before, just at the function declaration struct test get(int in);. Here's the rule 6.2.7:

2 All declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined.

From 6.7.6.3p15:

For two function types to be compatible, both shall specify compatible return types [...]

And from 6.2.7p1:

[...] two structure [...] declared in separate translation units are compatible if their tags and members satisfy the following requirements: [...] 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.

File 0.c declares function get at struct test get(int in); and file 1.c declares functions get at struct test get(int in){...} (definition is also a declaration). Both have the same name, so they refer to the same function.

Both have the return type struct test. In 0.c struct test has a member of type int, and in 1.c struct test has a member of type char. Types of the first pair of members of both structures in both files are not compatible, so types struct test are not compatible, so function declarations are not compatible, so the behavior of code is undefined.

CodePudding user response:

Is this Undefined Behaviour?

Yes.

C doesn't officially have the one dentition rule like C and this post says multiple definitions are ok? Are different translation units allowed to define structures with the same name?

C does not have the exactly the same one-definition rule that C has, but it does have similar rules. There can be at most one external definition of each identifier with external linkage anywhere in the program. There can be at most one definition of an identifier with internal linkage in any given translation unit. There can be at most one definition of an identifier with no linkage in the same namespace within the scope of that identifier, except that typedefs may be redefined identically.

The answer you referred to explains that because structure type declarations have no linkage, you can re-use structure tags in different translation units, but that is not sufficient for the needs of the code presented in this question.

Here, in order for the behavior of the program to be well defined, all declarations of function get() anywhere within must be compatible with each other (C17, 6.2.7/2). Declarations include definitions, so that means that the type specified by get() in its prototype in 0.c must be compatible with its definition in 1.c. "Compatible" is a defined term in C, covered by section 6.2.7 of the language specification, including several others by reference.

The rules for function declarations are in paragraph 6.7.6.3/15. The most relevant provision is the very first sentence:

For two function types to be compatible, both shall specify compatible return types.

We go back to 6.2.7/1 for the definition of structure type compatibility:

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; [...] and if one member of the pair is declared with a name, the other is declared with the same name. For two structures, corresponding members shall be declared in the same order.

Your two struct test types are (perforce) defined with the same tag, and their members have the same names in the same order, but their corresponding members do not have compatible types (details left as an exercise). As a result, the declaration of function get() in 0.c is not compatible with the definition in 1.c, and therefore the program has undefined behavior -- and still would even if get() were never called.

CodePudding user response:

The problem with such a code in C is that the compiler only stores external names of functions without providing information about their parameters and return types. So the both translation units do not see the declarations of the function in each other. They only provide the external name of the function get. And the linker thinks that the definition of the function corresponds to the both names get. But the referred structure types in the declarations and the definition are different and not compatible. So the program has undefined behavior.

  •  Tags:  
  • c
  • Related