4

(I am talking about C, but it also applies to class templates in C++)

In header file, it is a custom to put all the DECLARATIONS, not definitions. However, we usually put structure definitions or class templates in header file as well without actually knowing why we can. This doesn't really make sense because they are definitions as well -- ONE DEFINITION RULE. (Yes, structure definitions and class templates don't cause any storage to set, but you still get "redefinition" error below which implies that they are definitions).

EX) defining multiple structures with same tag within same file give you a redefinition error, but defining multiple structures with same tag in multiple source files don't cause any error (same thing happens with class).

The only thing that makes sense is that structure definitions and class templates have internal linkage (opposed to default external linkage), but I can't find any references about it in K&R or reference manual. In fact, structures are not even mentioned in linkage.

I want to know the exact reference where ANSI standard points out this pheonomenon. (IMO, this is a pretty ambiguous thing which HAS TO be mentioned in ANSI standard somewhere).


EDIT I am NOT asking why structure definitions can be put into the header file.

I am asking why putting structure definition in header file won't cause redefinition error like it does when we put variable definitions in header file (and include it in multiple source files)

EX) test1.c: int a = 3; test2.c: int a = 4; Causes compile error because of redefinition. However,

test1.c: struct test { int a }; test2.c: struct test { int b }; Does not cause compile error, and the only reason I can come up with is that structure definitions either have internal linkage, or no linkage at all.

SHH
  • 3,226
  • 1
  • 28
  • 41
  • What's "internal" linkage - do you mean "static"? – Kerrek SB Aug 14 '11 at 21:23
  • 1
    internal linkage as defined in http://publications.gbdirect.co.uk/c_book/chapter8/declarations_and_definitions.html – SHH Aug 14 '11 at 21:24
  • Standard C has the concept of "tentative definition". Try looking for that in K&R or reference manual. – pmg Aug 14 '11 at 21:25
  • 1
    OK, I see. You should decide whether you want C or C++. In C, structs are just types, they don't have any linkage. In C++ member definitions are inline, and inlined definitions are exempt from ODR if the content is the same everywhere. – Kerrek SB Aug 14 '11 at 21:29

5 Answers5

5

In C only objects and functions have linkage. Since struct in C may not contain functions or "static" member objects as in C++ your question makes not much sense, here.

Member functions in C++ as long as they are not defined but only declared inside the struct pose no problem. If they are also defined, they are inline. The concept of inline was just invented for C++ to capture that case: a function definition that can be shared through a header file in several compilation units. C99 that adopted that concept (modifying it slightly).

static member objects pose indeed more of a problem. The syntax on how to instantiate these guys is quite obscure, especially for template classes or structs. If you'd like to know about that one you'd have to ask for that, tagged specifically with C++.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • 2
    Structure identifiers have no linkage. That was the answer. Thank you very much! I verified this fact from ANSI standard specification: "The following identifiers have no linkage: an identifier declared to be anything other than an object or a function;" http://flash-gordon.me.uk/ansi.c.txt – SHH Aug 14 '11 at 22:15
2

Structures are defined in a header file because the header file provides the interface to a module. When the structure is defined in the interface, it is possible for the users of the interface to:

  • refer to the members of the structure
  • know how large the structure is - otherwise they couldn't allocate memory for the structure

Linkage has nothing to do with it - only functions are linked, not the data structures.

Note that you can still declare a structure in a header file, which is useful if you want to hide the internals of the structure (opaque data structure). Users of the interface can have pointers to the structure and use them as kind of a cookie, but they cannot allocate such a structure themselves, or "see" inside it.

As for not getting a redefinition error when defining a structure in a header file, that's simply because of header guards - a header typically looks like this:

#ifdef MYHEADER_H
#define MYHEADER_H

struct a { int x; }
void f(void);
/* and so on */

#endif

So when including a header file, it is usually included only once and therefore the structure is only defined once per translation file. The linker has nothing to do with the structure definitions as they have no linkage.

Antti
  • 11,944
  • 2
  • 24
  • 29
1

The struct line is merely a definition. The definition is not visible outside of the source file.
FYI: Neither source file exports anything.

To test this:

$ cat test1.c
struct test { char a; };
$ gcc -o test1.o -c test1.c
$ nm 
$ echo "struct test foo; " >> test1.c
$ gcc -o test1.o -c test1.c
$ nm
0000000000000001 C _foo
Foo Bah
  • 25,660
  • 5
  • 55
  • 79
0

I think you are mixing yourself up a bit here, you can put whatever you like in a header file.

The usual things to put in them are declarations of enums, typedefs, structs, and function prototypes so various C files can compile without having to have knowledge of the actual function or actual memory ( a struct basically is definition of how memory is laid out )

Keith Nicholas
  • 43,549
  • 15
  • 93
  • 156
  • I think you missed my point. Yes, we can put anything in the header file, but we usually put declarations only to avoid redefinition error. However, I am just wondering why structure definitions in header file won't cause redifinition error throughout multiple source files. – SHH Aug 14 '11 at 21:34
0

I don't have a copy of a final version, but from the n843 draft of the specification I see:

from 6.7.2.3 Tags: "4 Two declarations of structure, union, or enumerated types which are in different scopes or use different tags declare distinct types. Each declaration of a structure, union, or enumerated type which does not include a tag declares a distinct type."

from 6.2.1 Scopes of Identifiers: "4 Every other identifier has scope determined by the placement of its declaration (in a declarator or type specifier). If the declarator or type specifier that declares the identifier appears outside of any block or list of parameters, the identifier has file scope, which terminates at the end of the translation unit. [...]" [emphasis in original] (The only identifier type that I see mentioned in this section prior to this statement was labels, which have function scope.)

I'm no expert on C or the standards, but it looks to me like this explains the behavior you are seeing. So, a struct should have a collision if the file scope is the same and the struct has a duplicate tag, because having a distinct tag would be required to make them distinct types. But if they are in a different file scope, there's no problem, because as long as they are in different scopes, the requirements are met for being a distinct type.

shelleybutterfly
  • 3,216
  • 15
  • 32
  • As for the templates in C++, I am not sure if it's the same reason; if this doesn't answer your question I can try to track a C++ spec down. – shelleybutterfly Aug 14 '11 at 21:59
  • Thank you for your answer. The correct answer was that structures have no linkage. Your answer made me delve into ANSI standard specification, and I found the answer. "The following identifiers have no linkage: an identifier declared to be anything other than an object or a function;" flash-gordon.me.uk/ansi.c.txt – SHH Aug 14 '11 at 22:17
  • and I am pretty sure same thing applies to class templates as well :) – SHH Aug 14 '11 at 22:19
  • Terrific, I'm glad you found your answer! So, I'm a little confused, though; is what I posted incorrect? It seems like what the spec says here is that a struct in a different file can have the same tag; but if that's incorrect I'd like to be able to fix or remove my answer. As to what you were able to find, it would be very nice if we had the particular sections, etc. here in the answers; if possible, you should post an answer with a reference to the section and probably the relevant quotes, and just mark your answer as the accepted answer; if not, just put it into your question. :) – shelleybutterfly Aug 14 '11 at 23:00