7

Apparently,

For reasons that reach into the prehistory of C, it is possible to declare a struct and a non-struct with the same name in the same scope. - (Bjarne Stroustrup - The C++ Programming Language. 4th Edition)

For example:

struct Ambig {};

// the struct must be referred to with the prefix struct
void Ambig(struct Ambig* buf) {}

I'm just curious what the initial reason was? Without understanding, it seems like an example of bad language design, that causes ambiguity and is confusing.

Joe DF
  • 5,438
  • 6
  • 41
  • 63
Oleksiy
  • 37,477
  • 22
  • 74
  • 122
  • Perhaps this is what lead to the need to prepend `struct`. Could you point to your source for the quote? – Karthik T Aug 15 '13 at 08:40
  • @KarthikT Bjarne Stroustrup - The C++ programming language 4th Edition – Oleksiy Aug 15 '13 at 08:41
  • 3
    There's a ton of ways to cause semantic ambiguity and confusion, the responsibility of avoiding these lies with the programmer, not the language designer. There is no syntactic ambiguity since a `struct` prefix would imply that we're talking about the `struct`. – Bernhard Barker Aug 15 '13 at 08:49
  • @Dukeling True, but I thought it was designed that way for a good **reason**, that's why I'm asking. – Oleksiy Aug 15 '13 at 08:55
  • Look at http://stackoverflow.com/questions/1492735/differences-between-struct-in-c-and-c, too –  Aug 15 '13 at 09:00

4 Answers4

6

The reason, as stated in your quote from Stroustrup, is historical. In C, you must always prefix the name of the struct with struct; the name of the struct (like the name of unions or enums) is called a tag, and lives in a completely different name space than other symbols. So things like:

struct stat
{
    //  ...
};
int stat( char const* filename, struct stat* buf );

are perfectly legal. (The above is, in fact, part of Posix).

In C++, the name of a class (declared with class, struct or union) or an enum is in the same namespace as everything else, and unlike in C, you can write things like:

struct MyClass {};
MyClass variableName;

This would not be legal C. In C, the second line would have to be:

struct MyClass variableName;

The problem is that C++ needs to be able to use interfaces defined in C (like the Posix interface, above). So C++ defines some special rules to allow it: you can give a variable or a function and a class type the same name. When you do, the variable or function name has precedence, and hides the class name, except in "elaborated type specifiers" (i.e. class, struct, union or enum, followed by a symbol), where non-type names are ignored in the lookup.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
3

The reason it is like this has to do with C++ inheriting from C. It was not "added" to C++, it is there because it works that way in C.

In C, you have to use struct X and union Y (there is no class keyword in C), or use typedef struct X A; and then use the name A instead of strcut X (where X and A could be the same name).

In C++ the compiler will, as long as the name is unique, understand that X is referring to struct X. You don't have to type struct, union or class in front of the name, or use typedef to create a new, standalone name.

Since C++ is designed to allow (wherever possible) the use of C syntax, it is still allowed to write struct X when referring to a struct. This allows the use of a name that is otherwise ambiguous.

It is highly recommended to NOT make use of this "possibility" unless required by historical design decisions, because all it will achieve is more confusion...

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • Hi, it wasn't really my question - I know that it's optional to use struct in front of the name. But thanks for your effort, I'm sure some people will find it helpful! – Oleksiy Aug 15 '13 at 09:12
  • Re your last sentence, you don't always have a choice. Posix defines a `struct stat` and a function `stat()` (which takes a `struct stat*` as its second argument). If you want to use this function, you have to have a `struct stat` somewhere. – James Kanze Aug 15 '13 at 09:17
  • I've edited in a first paragraph to explain WHY it is this way. – Mats Petersson Aug 15 '13 at 09:18
  • @JamesKanze: I've added a "unless required by historical design decisions". – Mats Petersson Aug 15 '13 at 09:19
  • @MatsPetersson Well, I'm not sure that "design decisions" is the right word; I suspect that there is no "design" involved, and that it is more serendipity. But yes... – James Kanze Aug 15 '13 at 09:22
  • @JamesKanze: It is still a design decision to make it that way, even if was never written down anywhere outside the source codee, and the decision was done in about 0.5 seconds by someone high on caffeine late at night... ;) – Mats Petersson Aug 15 '13 at 09:24
3

I'm just curious what the initial reason was? Without understanding, it seems like an example of bad language design, that causes ambiguity and is confusing.

In C it's a first implementation of name spaces. Identifiers live in different name spaces and the idea is they can have the same name if they are declared in different name spaces. Name space for structure tags and ordinary identifiers are not the only two name spaces in C. There are four name spaces in C:

(C99, 6.2.3 Name spaces of identifiers p1) "Thus, there are separate name spaces for various categories of identifiers, as follows:

— label names (disambiguated by the syntax of the label declaration and use);

— the tags of structures, unions, and enumerations (disambiguated by following any24) of the keywords struct, union, or enum);

— the members of structures or unions; each structure or union has a separate name space for its members (disambiguated by the type of the expression used to access the member via the . or -> operator);

— all other identifiers, called ordinary identifiers (declared in ordinary declarators or as enumeration constants)."

ouah
  • 142,963
  • 15
  • 272
  • 331
  • At least in the earliest versions of C (and I think even today), there is exactly one namespace for all members of struct et al., and the names of the members of different structs could not conflict. This is why the members of most structs traditionally start with a prefix; e.g. in `struct tm`, you have `tm_year`, and not just `year`. – James Kanze Aug 15 '13 at 09:15
  • @JamesKanze At least not in Standard C as *each structure or union has a **separate name space **for its members*. – ouah Aug 15 '13 at 09:18
  • 1
    Which makes sense. But it wasn't that way in K&R I. And I can remember tracking down errors due to `C* cp; /*...*/ cp->memberOfD;` Not just no error, but not even a warning (unless you used `lint`). – James Kanze Aug 15 '13 at 09:24
1

Well adding struct before structs is perfectly legal C. Therefore some C code also applies to C++.
What did you expect? C++ is based on C.

In c++ we avoid using struct before every struct. I've never actually seen it in production code.

Regarding ambiguity, I don't think anyone knows why they allowed that. But I believe it's because the ambiguity is resolved when you add struct. You essentially tell the compiler that this is not a function and therefore that possible meaning is eliminated.

gifnoc-gkp
  • 1,506
  • 1
  • 8
  • 17
  • Thanks for your answer! Sorry, what do you mean "we avoid using struct before every struct"? – Oleksiy Aug 15 '13 at 08:53
  • 1
    @Oleksiy he just means that c++ compilers are smart enough to know you're referring to a struct so prefixing it with keyword "struct" is not necessary – greatwolf Aug 15 '13 at 08:55
  • 1
    There are several problems with this answer. The first is using the `struct` keyword systematically when a type name is involved is not only legal in C, it is required. And C interfaces (like that of Posix) _do_ have functions and structs with the same name, so there are cases where you have to do so in C++. Which is the real reason why it is allowed. – James Kanze Aug 15 '13 at 09:20