15

Suppose I have a.c and b.c, which both define types called struct foo, with different definitions:

#include <stdio.h>

struct foo {
    int a;
};

int a_func(void) {
    struct foo f;
    f.a = 4;
    printf("%d\n", f.a);
    return f.a * 3;
}

 

#include <stdio.h>

struct foo { // same name, different members
    char *p1;
    char *p2;
};

void b_func(void) {
    struct foo f;
    f.p1 = "hello";
    f.p2 = "world";
    printf("%s %s\n", f.p1, f.p2);
}

In C, can these files both be linked together as part of a standards-conforming program?

(In C++, I believe this is forbidden by the One Definition Rule.)

user253751
  • 57,427
  • 7
  • 48
  • 90
  • 2
    Sure... as long as only one definition is visible in any given context. But watch out with extern, that you don't link to an object created with a different definition than the one you access it with... – Dmitri Dec 23 '15 at 00:21
  • As dimitri said, techincally yes, but I would say it's less than ideal coding style. – Taelsin Dec 23 '15 at 00:26
  • 1
    There's nothing wrong with the coding style, and extern has nothing to do with it. – Jim Balter Dec 23 '15 at 06:08
  • @JimBalter if "file1.c" contains, for example: `typedef float typeA; typeA x=1.2;` and "file2.c" contains `typedef int typeA; extern typeA x;` then what happens when they're compiled and linked together? Both units access the same object from `file1.c` but `file2.c` does it with the wrong effective type, since it sees a different (incompatible) definition for `typeA` where its extern declaration for `x` is. That's how extern is relevant... one needs to make sure any extern declarations use the same type definition that the actual external object does. – Dmitri Dec 23 '15 at 18:44
  • @Dmitri That has absolutely nothing to do with the issue here ... it has everything to do with having two different externally linked variables with the same name: `x`. The linker doesn't "see" any definition for `typeA` -- those types are completely local to the source file they are in. It would still be a bug if you simply did `float x=1.2;` in one file and `extern int x;` in the other, of course ... how could you not know this? It's fundamental. Look, I was on the C standards committee, and programmed in C since the mid 70's, so don't try to pull one over on me. – Jim Balter Dec 23 '15 at 23:26
  • 1
    And people who mention "coding style" here have never worked on more than a toy program and don't understand the basics of programming. When you have programs with hundreds or thousands of modules, written by dozens of programmers, and linked with numerous libraries, then of course you will numerous different type definitions with the same name. Every tree implementation in the library is likely to have a struct called `Node`. This is normal and good. Externally linked variables and functions are a *completely different matter*, not related to this question. [My last comment here.] – Jim Balter Dec 23 '15 at 23:37
  • 1
    @JimBalter Nobody's "pulling one over on you", nor saying that the linker sees different definitions of the type. The point was that when an extern object is to be linked to from different source files it's necessary to ensure that the different declarations actually refer to the same kind of data, and not just the same type name. You obviously know this.. as you say, "it's fundamental".. so I don't know what you're getting so worked up about. – Dmitri Dec 24 '15 at 04:27

3 Answers3

10

Struct tags are identifiers with no linkage (C11 6.2.2/6)

The rules about multiple definitions of identifiers with no linkage are found in 6.7/3:

If an identifier has no linkage, there shall be no more than one declaration of the identifier (in a declarator or type specifier) with the same scope and in the same name space, except that:

  • a typedef name may be redefined to denote the same type as it currently does, provided that type is not a variably modified type;
  • tags may be redeclared as specified in 6.7.2.3.

In your program, the two declarations of foo are in different scopes , so the condition "with the same scope" is not satisfied and therefore this rule is not violated.

M.M
  • 138,810
  • 21
  • 208
  • 365
2

The way to think about this is in terms of compilation units. A .c file, along with nested hierarchy of included .h files, comprise a single compilation unit. The pre-processor expands all the .h files, and presents the entire compilation unit to the compiler.

A compilation unit is a closed namespace for macros, type names, static identifiers, enums etc. These names cannot have duplicates within this namespace, and none of these names are visible outside this namespace. The implication is that a different compilation unit is a separate, closed namespace - and may reuse the same identifiers, as long as there are no duplicates within that namespace.

Therefore, you may use the same name for certain identifiers, as long as these are in separate compilation unit namespaces.

Note that externally visible identifiers like non-static global variables, functions etc. need to be unique across the entire external namespace, which spans all the compilation units linked together into a single executable.

Ziffusion
  • 8,779
  • 4
  • 29
  • 57
  • Where you say "namespace" , the Standard C term is "scope". In Standard C, "namespace" is not a thing, and "name space" means something else. Your "external namespace" would be describing the collection of "identifiers with external linkage" – M.M Dec 23 '15 at 02:03
  • 3
    `namespace` as used here is a general term. There are systems (languages) where this term is explicitly adopted to imply similar semantics. But a `namespace` is a common term in computing. – Ziffusion Dec 23 '15 at 02:10
-2

In the C programming language, it doesn't matter what you call your types. Symbols are typed according to the structure of the type, not according to the type names. It is completely legal to use the same structure name for different structure types in different files. You can however not use different types to declare the same function.

fuz
  • 88,405
  • 25
  • 200
  • 352
  • 2
    This is quite confused. C has nominal, not structural, types. The issue here has nothing to do with that, but rather is about scope. Since the symbols are defined in different scopes, they are independent. – Jim Balter Dec 23 '15 at 06:06