Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Same struct with different definitions in translation units

Tags:

c

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?

like image 264
Dan Avatar asked Jan 24 '26 07:01

Dan


2 Answers

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.

like image 193
KamilCuk Avatar answered Jan 25 '26 20:01

KamilCuk


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.

like image 21
John Bollinger Avatar answered Jan 25 '26 21:01

John Bollinger



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!