Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

structure tag in C vs C++

I wrote following simple program & compiled it on gcc compiler

#include <stdio.h>
typedef int i;
void foo()
{
    struct i {i i;} i;
    i.i = 3;
    printf("%i\n", i.i);
}
int main() { foo(); }

It compiles & runs fine in C.(See live demo here) But it fails in compilation in C++. C++ compiler gives following error messages.

prog.cc: In function 'void foo()':
prog.cc:5:17: error: field 'i' has incomplete type 'foo()::i'
     struct i {i i;} i;
                 ^
prog.cc:5:12: note: definition of 'struct foo()::i' is not complete until the closing brace
     struct i {i i;} i;

See live demo here

I couldn't find rules regarding this in C & C++ standards. Why it compiles fine in C but not in C++ ? What does the standard says about this ? I very well know that C & C++ are different languages having different rules but I am curious to know about exact rules.

like image 552
Destructor Avatar asked Nov 13 '16 18:11

Destructor


People also ask

What is a structure tag in C?

An optional identifier, called a "tag," gives the name of the structure type and can be used in subsequent references to the structure type. A variable of that structure type holds the entire sequence defined by that type. Structures in C are similar to the types known as "records" in other languages.

Is structure tag mandatory in C?

Note: In C++, the struct keyword is optional before in declaration of a variable. In C, it is mandatory.

Is structure available in C?

In C programming, a struct (or structure) is a collection of variables (can be of different types) under a single name.


1 Answers

The difference between C and C++ is the following. In C the data member i is considered as having type int because if you wanted that it had type struct i then you have to write struct i i specifying the keyword struct before i.

Structure tags are in their own namespace compared with the namespace of other variables.

According to the C Standard (6.2.3 Name spaces of identifiers)

1 If more than one declaration of a particular identifier is visible at any point in a translation unit, the syntactic context disambiguates uses that refer to different entities. 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 any32) 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).

As for C++ then inside the structure definition the name of the structure hides the name of the typedef and the compiler issues the error. In C++ there is separate class scope.

For example in C++ (3.4 Name lookup) there is written

3 The injected-class-name of a class (Clause 9) is also considered to be a member of that class for the purposes of name hiding and lookup.

and (3.4.1 Unqualified name lookup)

7 A name used in the definition of a class X outside of a member function body or nested class definition29 shall be declared in one of the following ways: — before its use in class X or be a member of a base class of X (10.2), or ...

Thus the injected name of the class hides the typedef name within the class definition.

Take into account that outside the class definition the name of the class can be hidden by the same name of an object. Thus if you want to declare an object of the class in that scope you have to use its elaborated name like

int i;

struct i {};

//...

struct i obj;
like image 118
Vlad from Moscow Avatar answered Oct 16 '22 08:10

Vlad from Moscow