Motivated by the discussion
The grammar for C++ classes is defined as
class-key identifier *[opt]* base-clause *[opt]* (Italics are mine)
This to me means that the class name is option and we can have unnamed classes in C++.
So, is the following well-formed?
struct X{
struct{
int x;
int y;
};
};
int main(){}
VS: error C2467: illegal declaration
of anonymous 'struct'
Comeau online: error: declaration does
not declare anything
struct{
GCC(ideone): Compiles fine
Any thoughts?
No, it is not well-formed. You cannot derive the language syntax from these grammar statements alone. The extra requirements are given in the text of the standard also have to be taken into account. In this case that would be
7 Declarations
...
3 In a simple-declaration, the optional init-declarator-list can be
omitted only when declaring a class
(clause 9) or enumeration (7.2), that
is, when the decl-specifier-seq
contains either a class-specifier, an
elaboratedtype-specifier with a
class-key (9.1), or an enum-specifier.
In these cases and whenever a
class-specifier or enum-specifier is
present in the decl-specifier-seq, the
identifiers in these specifiers are
among the names being declared by the
declaration (as class-names,
enum-names, or enumerators, depending
on the syntax). In such cases, and
except for the declaration of an
unnamed bit-field (9.6), the
decl-specifier-seq shall introduce one
or more names into the program, or
shall redeclare a name introduced by a
previous declaration.
The last sentence is the one that matters in this case
The "optional" part is only there to allow declarations like
struct { int x; } s;
typedef struct { int x, y; } Point;
The first one which declares a class type with no linkage and variable s of that type. Note that types with no linkage cannot be used to declare a variable with linkage, meaning that such declaration cannot be used in namespace scope.
Your example is ill-formed, but this would be legal
struct X {
struct {
int x;
int y;
} point;
};
Also, nameless class syntax is used to declare anonymous unions (although I'm a bit puzzled by the fact that 7/3 does not mention anonymous unions).
That code is actually valid in MSVC, you must have compiled in a restricted mode.
And while I would most likely never use them, they do allow for some interesting usage, like this:
X obj;
obj.x=1;
obj.y=2;
They're used for example in the LARGE_INTEGER class, only it's an union instead. This way you can avoid sub-objects when all you really want is one member to be splittable into smaller pieces.
The LARGE_INTEGER declaration as a visual example:
#if defined(MIDL_PASS)
typedef struct _LARGE_INTEGER {
#else // MIDL_PASS
typedef union _LARGE_INTEGER {
struct {
DWORD LowPart;
LONG HighPart;
};
struct {
DWORD LowPart;
LONG HighPart;
} u;
#endif //MIDL_PASS
LONGLONG QuadPart;
} LARGE_INTEGER;
As far as I know however, this isn't valid standard C++, it's only allowed as extensions in gcc and msvc.
Related
I got this implementation of a struct:
struct NodoQ {
Etype elem;
NodoQ *sig;
};
Is this code below,
typedef NodoQ *PtrNodoQ;
PtrNodoQ ppio, fin;
the same as this one?
NodoQ* ppio;
NodoQ* fin;
Is this code below,
typedef NodoQ *PtrNodoQ;
PtrNodoQ ppio, fin;
the same as this one?
NodoQ* ppio;
NodoQ* fin;
Yes, it's resulting in the exactly same pointer types for ppio and fin.
As for your comment
"I didn't try cause I got the second option everywhere in my code, and just didn't want to loose some time... "
You can easily test it:
void foo(PtrNodoQ p) {
}
void bar(NodoQ* p) {
foo(p);
}
and
void baz() {
NodoQ n;
foo(&n);
bar(&n);
}
compile all perfectly fine, without invalid type conversion warnings or errors.
Also you could have found the answer quickly in this excellent reference (emphasis mine):
The typedef-names are aliases for existing types, and are not declarations of new types. Typedef cannot be used to change the meaning of an existing type name (including a typedef-name). Once declared, a typedef-name may only be redeclared to refer to the same type again. Typedef names are only in effect in the scope where they are visible: different functions or class declarations may define identically-named types with different meaning.
In case you wanted the standardese, [dcl.typedef] states that:
A name declared with the typedef specifier becomes a typedef-name. Within the scope of its declaration, a
typedef-name is syntactically equivalent to a keyword and names the type associated with the identifier in
the way described in Clause 8. A typedef-name is thus a synonym for another type. A typedef-name does
not introduce a new type the way a class declaration (9.1) or enum declaration does. [ Example: after
typedef int MILES, *KLICKSP;
the constructions
MILES distance;
extern KLICKSP metricp;
are all correct declarations; the type of distance is int and that of metricp is “pointer to int.” —end
example ]
In your case, after
typedef NodoQ *PtrNodoQ;
The types PtrNodoQ and Node* are exactly the same and can be used interchangeably from there on out. The declarations NodoQ* ppio; and PtrNodoQ ppio; are exactly equivalent.
The following code (live example) does not compile:
struct S {};
typedef struct S T;
S s = T(); // OK
struct T * p; // error: elaborated type refers to a typedef
T::T(){} // error: C++ requires a type specifier for all declarations
Why is the language designed to not permit the last two lines?
Relevant Standard quote (N4140 §7.1.3/8):
[ Note: A typedef-name that names a class type, or a cv-qualified version thereof, is also a class-name (9.1).
If a typedef-name is used to identify the subject of an elaborated-type-specifier (7.1.6.3), a class definition (Clause 9), a constructor declaration (12.1), or a destructor declaration (12.4), the program is ill-formed.
—end note ]
So there are three unrelated issues. The first one you have in the quote you provide:
struct T * p;
That is illegal as T is a typedef.
T{};
That is illegal at namespace level, but would be legal in other concepts, for example as part of the initialization of a global, or inside a function:
T t = T{};
void f() { T{}; }
It really means to create a value-initialized temporary object of type T.
T::T(){}
That would be a valid definition for a default constructor, except that you did not declare one. If you modify the S to have a user declared default constructor that would work:
struct S { S(); };
Why is the language designed to not permit the last two lines?
Those two lines, in the updated question are:
struct T* p;
T::T() {}
The second one is legal, but you are trying to define a function that has not been declared as a member, so this is also unrelated to the original text. Which leaves us with one: struct T* p.
The motive comes from C. The identifiers for user defined types and other names appear to live in different scopes, when lookup is trying to resolve a name not qualified with struct or enum, it will ignore struct and enums, when trying to resolve a struct or enum it ignores everything else. The following is valid C (and C++):
struct T {}; // 1
typedef struct S {} T; // 2
struct T t;
In C++ the rules for lookup changed a bit and you can use the type specifiers without explicitly qualifying it but that is a different thing. Additionally, typedef-ed names can be used in other contexts that were not possible in C.
An special case is lookup for an elaborated type specifier, should the typedef-ed name be usable in an elaborated type specifier? If it was, the semantics of the program above would change and where in C t is of type T (defined in 1), in C++ it would become S (defined in 2).
Note that this is to some extent a wild guess, I did not make the rules and I don't know what went into consideration there. Note that C and C++ were never really compatible in this respect, a similar example changes semantics in C and C++:
int T;
void f() {
struct T { int data[10]; };
printf("%d\n", sizeof(T));
}
That program will print a number 10x larger in C++ than in C. But the ability to use a type without having to qualify it with class or struct was probably more important than breaking compatibility in a few cases...
I have the following (working) code in an existing code base, used in include file that is shared between C and C++, compiling on MSVC (2010) and Windows DDK:
struct X {
USHORT x;
} typedef X, *PX;
And:
enum MY_ENUM {
enum_item_1,
enum_item_2
} typedef MY_ENUM;
As far as I know, correct definition should look like this:
typedef struct {
USHORT x;
} X, *PX;
Is there any purpose for having the form below? Am I missing something?
The fact that both typedef <type> <alias> and <type> typedef <alias> are valid simply comes from the language grammar definition.
typedef is classified as a storage-class specfifier (just like static, auto), and the type itself is known as the type-specifier. From the syntax definitions in section 6.7 of the standard, you'll see that these are free to be interchanged:
declaration:
declaration-specifiers init-declarator-list ;
declaration-specifiers:
storage-class-specifier declaration-specifiers
type-specifier declaration-specifiers
type-qualifier declaration-specifiers
function-specifier declaration-specifiers
init-declarator-list:
init-declarator
init-declarator-list , init-declarator
init-declarator:
declarator
declarator = initializer
(Note, of course, that this is equally true for structs and for non-structs, meaning that double typedef trouble; is also valid.)
As others said, typedef is a storage-class specifier and as with other storage-class specifiers you are also allowed to put the specifier between the type and the declarator.
While this is valid and it is also a form that should be avoided as C marked it as an obsolescent feature:
(C11, 6.11.5p1) "The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature."
Both have the same meaning. Both of these two forms are valid:
typedef <existing_type> <new_type>
<existing_type> typedef <new_type>
You can typedef the above struct in either ways:
struct X {
USHORT x;
}typedef X, *PX; // <existing_type> typedef <new_type>
or
typedef struct {
USHORT x;
} X, *PX; // typedef <existing_type> <new_type>
You really are allowed to put all the declaration specifiers in any order you want! The positions of any * pointers and the actual declarator (the variable or new type name) matter, but all that typedef int unsigned const static etc. stuff can be in any order.
If you look at the official grammar of C, it just says:
declaration:
declaration-specifiers init-declarator-list ;
The declaration-specifiers are all the storage class specifiers (typedef, extern, etc.), type specifiers (the actual type, like int or struct X), type qualifiers (const and volatile), and a few other less common ones. Their order is not important. The second part is the init-declarator-list, and it's the variable or new type name (in the case of a typedef), any * characters, the initialization of the variable (int x = 3), and more. The order of things in the declarator part is important, but not the order in the declaration specifiers.
Disclaimer: This is not a technical but a practical answer. Refer to the other answers for technical matters. This answer reads opinionated and subjective but please bear with me while I try to explain the bigger picture.
struct is a strange beast because the stuff you put between the closing bracket } and the semicolon ; refers to the content inside or before those brackets. I know why that is, and grammatically it does make sense, but personally I find it very counter-intuitive as curly brackets usually mean scope:
Counter-intuitive examples:
// declares a variable named `foo` of unnamed struct type.
struct {
int x, y;
} foo;
foo.x = 1;
// declares a type named `Foo` of unnamed struct type
struct {
int x, y;
} typedef Foo;
Foo foo2;
foo2.x = 2;
// declares a type named `Baz` of the struct named `Bar`
struct Bar {
int x, y;
} typedef Baz;
// note the 'struct' keyword to actually use the type 'Bar'
struct Bar bar;
bar.x = 3;
Baz baz;
baz.x = 4;
There are so many subtle things that can go wrong with the dense syntax of structs and typedefs if used like this. As shown below it is very easy to declare a variable instead of a type by accident. The compiler is only of limited help because almost all combinations are grammatically correct. They just don't necessarily mean what you try to express. It is a pit of despair.
Wrong examples:
// mixed up variable and type declaration
struct foo {
int x, y;
} Foo;
// declares a type 'foo' instead of a variable
typedef struct Foo {
int x, y;
} foo;
// useless typedef but compiles fine
typedef struct Foo {
int x, y;
};
// compiler error
typedef Foo struct {
int x, y;
};
For reasons of readability and maintenance I prefer to declare everything separately and never put anything behind the closing curly bracket. The cost of additional lines of code are easily outweighed by intuitive syntax. I argue that this approach makes it easy to do the right things and annoying to do the wrong things.
Intuitive examples:
// declares a struct named 'TVector2'
struct TVector2 {
float x, y;
};
// declares a type named 'Vector2' to get rid of the 'struct' keyword
// note that I really never use 'TVector2' afterwards
typedef struct TVector2 Vector2;
Vector2 v, w;
v.x = 0;
v.y = 1;
MSDN reckons that anonymous structs are non-standard in C++:
A Microsoft C extension allows you to declare a structure variable
within another structure without giving it a name. These nested
structures are called anonymous structures. C++ does not allow
anonymous structures.
You can access the members of an anonymous structure as if they were
members in the containing structure.
#K-ballo agrees.
I'm told that this feature isn't necessarily the same as just creating an unnamed struct but I can't see a distinction in terms of standard wording.
C++11 says:
[C++11: 9/1]: [..] A class-specifier whose class-head omits the class-head-name defines an unnamed class.
and provides an entire grammatical construction for a type definition missing a name.
C++03 lacks this explicit wording, but similarly indicates that the identifier in a type definition is optional, and makes reference to "unnamed classes" in 9.4.2/5 and 3.5/4.
So is MSDN wrong, and these things are all completely standard?
Or is there some subtlety I'm missing between "unnamed structs/classes" and the same when used as members that prevents them from being covered by this C++03/C++11 functionality?
Am I missing some fundamental difference between "unnamed struct" and "anonymous struct"? They look like synonyms to me.
All the standard text refers to creating an "unnamed struct":
struct {
int hi;
int bye;
};
Just a nice friendly type, with no accessible name.
In a standard way, it could be instantiated as a member like this:
struct Foo {
struct {
int hi;
int bye;
} bar;
};
int main()
{
Foo f;
f.bar.hi = 3;
}
But an "anonymous struct" is subtly different — it's the combination of an "unnamed struct" and the fact that you magically get members out of it in the parent object:
struct Foo {
struct {
int hi;
int bye;
}; // <--- no member name!
};
int main()
{
Foo f;
f.hi = 3;
}
Converse to intuition†, this does not merely create an unnamed struct that's nested witin Foo, but also automatically gives you an "anonymous member" of sorts which makes the members accessible within the parent object.
It is this functionality that is non-standard. GCC does support it, and so does Visual C++. Windows API headers make use of this feature by default, but you can specify that you don't want it by adding #define NONAMELESSUNION before including the Windows header files.
Compare with the standard functionality of "anonymous unions" which do a similar thing:
struct Foo {
union {
int hi;
int bye;
}; // <--- no member name!
};
int main()
{
Foo f;
f.hi = 3;
}
† It appears that, though the term "unnamed" refers to the type (i.e. "the class" or "the struct") itself, the term "anonymous" refers instead to the actual instantiated member (using an older meaning of "the struct" that's closer to "an object of some structy type"). This was likely the root of your initial confusion.
The things that Microsoft calls anonymous structs are not standard. An unnamed struct is just an ordinary struct that doesn't have a name. There's not much you can do with one, unless you also define an object of that type:
struct {
int i;
double d;
} my_object;
my_object.d = 2.3;
Anonymous unions are part of the standard, and they have the behavior you'd expect from reading Microsoft's description of their anonymous structs:
union {
int i;
double d;
};
d = 2.3;
The standard talks about anonymous unions: [9.5]/5
A union of the form
union { member-specification } ;
is called an anonymous union; it defines an unnamed object of unnamed type. The member-specification of an anonymous union shall only define non-static data members. [ Note: Nested types and functions cannot be declared within an anonymous union. —end note ] The names of the members of an anonymous union shall be distinct from the names of any other entity in the scope in which the anonymous union is declared. For the purpose of name lookup, after the anonymous union definition, the members of the anonymous union are considered to have been defined in the scope in which the anonymous union is declared. [ Example:
void f() {
union { int a; const char* p; };
a = 1;
p = "Jennifer";
}
Here a and p are used like ordinary (nonmember) variables, but since they are union members they have the same address. —end example ]
The anonymous structs that Microsoft talks about is this feature for unions but applied to structs. Is not just an unnamed definition, its important to note that mebers of the anonymous union/struct are considered to have been defined in the scope in which the anonymous union/struct is declared.
As far as I know, there is no such behavior for unnamed structs in the Standard. Note how in the cited example you can achieve things that wouldn't be otherwise possible, like sharing storage for variables in the stack, while anonymous structs bring nothing new to the table.
This is a follow-up question.
In the previous question, #JohannesSchaub-litb said that the following code is not fully standard-conformant:
class { int i; }; //unnamed-class definition. § 9/1 allows this!
and then he added,
while it is grammatically valid, it breaks the rule that such a class must declare at least one name into its enclosing scope.
I couldn't really understand this. What name is he talking about?
Could anyone elaborate on this further (preferably quoting the Standard)?
Clause 9 of the standard allows class {public: int i;} (note the lack of a final semicolon) because this decl-specifier-seq for an unnamed class might be used in some other construct such as a typedef or a variable declaration. The problem with class {public: int i;}; (note that the final semicolon is now present) is that this class specification now becomes a declaration. This is an illegal declaration per clause 7, paragraph 3 of the standard:
In such cases, and except for the declaration of an unnamed bit-field (9.6), the decl-specifier-seq shall introduce one or more names into the program, or shall redeclare a name introduced by a previous declaration.
The point is that by declaring class{ int i; }; you are assembling a bunch of symbol (int i, in this case) you will not be able to use anywhere else in whatever code.
For this code to make sense you should at least do one of the following:
class Myclass { int i; }; //I can furthermore instantiate variables of Myclass
class { int i; } myvar; //This in fact creates a myvar object
typedef class { int i; } MyType; //I can funthermore instantiate variables of MyType
By saying just class{ int i; }; you are saying to the compiler:
keep an int and name it i,
wrap it into a class I'll never call and...
forget it! (};)
If you remove that declaration from your program, nothing will change.
class { int i; }; is not a valid declaration because it is a simple-declaration without an init-declarator-list but it doesn't introduce (or re-declare) a class name.
ISO/IEC 14882:2011 7 [dcl.dcl] / 3:
In a simple-declaration, the optional init-declarator-list can be omitted only when declaring a class (Clause 9) or enumeration (7.2), that is, when the decl-specifier-seq contains either a class-specifier, an elaboratedtype-specifier with a class-key (9.1), or an enum-specifier. In these cases and whenever a class-specifier or enum-specifier is present in the decl-specifier-seq, the identifiers in these specifiers are among the names being declared by the declaration (as class-names, enum-names, or enumerators, depending on the syntax). In such cases, and except for the declaration of an unnamed bit-field (9.6), the decl-specifier-seq shall introduce one or more names into the program, or shall redeclare a name introduced by a previous declaration.
The error message from GCC explains it quite succinctly:
$ cat > a.cc
class { int i; };
$ g++ -Wall -std=c++98 a.cc
a.cc:1: error: abstract declarator ‘<anonymous class>’ used as declaration
class { int i; } is an abstract-declarator (Standard, §8) but not a valid declaration (§7). That's the rule that #JohannesSchaub-litb referenced: for a valid declaration, you need something to be declared, e.g. a class name or variable name.
You are breaking the the [basic.scope.pdecl]/6, which says :
The point of declaration of a class first declared in an elaborated-type-specifier is as follows:
— for a declaration of the form
class-key attribute-specifier-seqopt identifier ;
the identifier is declared to be a class-name in the scope that contains the declaration, otherwise
— for an elaborated-type-specifier of the form
class-key identifier
if the elaborated-type-specifier is used in the decl-specifier-seq or parameter-declaration-clause of a
function defined in namespace scope, the identifier is declared as a class-name in the namespace that
contains the declaration; otherwise, except as a friend declaration, the identifier is declared in the
smallest namespace or block scope that contains the declaration. [ Note: These rules also apply within
templates. — end note ] [ Note: Other forms of elaborated-type-specifier do not declare a new name,
and therefore must refer to an existing type-name. See 3.4.4 and 7.1.6.3. — end note ]
you are not creating a variable of an anonymous type
you are not create a type
There is another example (in [basic.def]/2) from the standard that proves your example is not standard compliant :
struct S { int a; int b; }; // defines S, S::a, and S::b
struct X { // defines X
int x; // defines non-static data member x
static int y; // declares static data member y
X(): x(0) { } // defines a constructor of X
};
int X::y = 1; // defines X::y
enum { up, down }; // defines up and down
namespace N { int d; } // defines N and N::d
namespace N1 = N; // defines N1
X anX; // defines anX
Your example doesn't define anything (except an anonymous struct, who's fields can not be accessed).
Note an exception about the enum, because this case introduces two values to use.