4
#include<iostream>
using namespace std;

struct a{
    int e;
    struct abc *d;
};

struct abc{
    int c;
};

int main()
{
 return 0;  
}

I have defined the struct abc after definition of struct a in which i have declared a structure pointer for abc. This is supposed to throw compilation error because abc is used before its declaration. But, it doesn't, why? Whereas when i replace it with just struct abc d instead of struct abc *d, it is giving compilation error as expected.

Jeyaram
  • 9,158
  • 7
  • 41
  • 63
  • Having a pointer to an unknown data-type needs no extra information.- A pointer is a pointer. On the other hand, having an instance of an unknown data-type cannot be resolved, since you need to know the size of the structure to allocate space for it. – enhzflep Aug 07 '15 at 10:42
  • No, it's not used. The compiler knows the size of a *pointer* to a struct, because those pointers are always of the same size. – Bo Persson Aug 07 '15 at 10:42
  • poorly researched question. – vish4071 Aug 07 '15 at 10:46
  • @BoPersson but there are architectures that `sizeof(char*) != sizeof(int*)` [Can the size of pointers vary between data and function pointers?](http://stackoverflow.com/q/1473935/995714) [Are there are any platforms where pointers to different types have different sizes?](http://stackoverflow.com/a/1539196/995714) how can the compiler knows the pointer size in those cases? – phuclv Aug 07 '15 at 11:19
  • @LưuVĩnhPhúc - True, but pointers to structs and classes are required to all have the same size on a given system. – Bo Persson Aug 07 '15 at 11:23
  • @BoPersson: The entire purpose of the question is "how does the compiler know `abc` _is_ a class" (C++ does not have struct[ure]s) – Lightness Races in Orbit Aug 07 '15 at 12:05
  • @alain: Note that the question in the post body _is_ the question, not "a follow-up question". You cannot reasonably suggest that the entire primary question is whatever is written in the post title and nothing else, and that any text in the post body is just an addendum. The title is only there to summarise and identify the question; nothing more. – Lightness Races in Orbit Aug 07 '15 at 15:55

5 Answers5

6

This declaration

struct abc *d;

on the one hand declares struct abc and on the other hand declares pointer d of type struct abc *.

In this declaration there is no need to have the exact definition of struct abc because no data member of the structure is used.

This specifier struct abc is called elaborated type specifier.

It introduces a new type in the given scope or refers to an already declared type.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
5

You're right in that, usually, you'd need a forward declaration of such a type:

// Forward declaration
struct bar;

struct foo
{
    bar* d;   // only a pointer-to-bar; forward declaration sufficient
};

struct bar
{
    int c;
};

However, you are (for some reason) using the antiquated idiom of writing struct before the type name. (This was required in C but has never been in C++.)

struct foo
{
    struct bar* d;
};

struct bar
{
    int c;
};

Because you write struct bar there instead of just bar, that itself counts as a forward declaration of sorts. The compiler now knows that bar is a type and that's all it needs to know.

It's a bit obscure and subtle, but that's why you do not need the prior forward declaration any more.

[C++11: 3.1/4]: [ Note: A class name can also be implicitly declared by an elaborated-type-specifier (7.1.6.3). —end note ]

[C++11: 3.3.2/6]: 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 ]

[C++11: 3.4.4/2]: [..] If the elaborated-type-specifier is introduced by the class-key and this lookup does not find a previously declared type-name, or if the elaborated-type-specifier appears in a declaration with the form:

   class-key attribute-specifier-seqopt identifier ;

the elaborated-type-specifier is a declaration that introduces the class-name as described in 3.3.2.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
2

It works, because the compiler has all the information it needs:

  • the size of d (= size of pointer)1, and
  • what abc is (it's a struct).

If you stored an object of type struct abc instead:

struct abc d;

it would result in an error because the information about the size and memory layout of d is missing (because struct abc hasn't been defined yet).

Also if you left out the struct keyword:

abc *d;

then the information about what abc is would be missing, and it would be an error as well.


This is supposed to throw compilation error because abc is used before its declaration.

It is not used, it is only declared. Using abc via a pointer would require dereferencing the pointer first (and if abc is not defined at that point, it would be an error).


1 Pointers to incomplete types are allowed because the size and memory layout of a pointer doesn't depend on what it points to.

Emil Laine
  • 41,598
  • 9
  • 101
  • 157
0

Pointer declared to incomplete types are allowed .

This is forward declaration-

Forward declaration is a declaration preceeding an actual definition, usually for the purpose of being able to reference the declared type when the definition is not available. Of course, not everything may be done with the declared-not-defined structure, but in certain context it is possible to use it. Such type is called incomplete.

A declaration of the following form

  class-key attr identifier ;   // struct abc *d; (Your case)

Declares a class type which will be defined later in this scope. Until the definition appears, this class name has incomplete type.

When struct a is declared it doesn't know the specs of struct abc yet, but you can forward reference it.

ameyCU
  • 16,489
  • 2
  • 26
  • 41
-2

In struct a you refer to a pointer to struct abc, so the compiler has no need for more information about it to compute the size of the d member.

In a later stage, it will check that struct abc is defined, if needed (for exemple if it is dereferenced). This explains the rationale for the standard which

  • forbids to declare variables of unknown type (abc, when not forwarded, is such an unknown type)

  • allows to declare them as pointers to incomplete type. (struct abc is an incomplete type: at least it is known to be some struct).

Practically, declaring a structure as

 struct a {
    struct abc *d;
 }

amounts to forwarding the declaration of (struct) type abc, as in

struct abc;           // forward
struct a {
   abc *d;            // legal
};

However the type abc is incomplete, so the following is illegal

struct z {
   struct abc y;   // error : incomplete struct type
}

For the curiosity, this is OK:

struct A {
   struct B* ptr1;    // forwards declaration of B, and use it
   B* ptr2;           // B is a known (incomplete-)type name now
} 
Michel Billaud
  • 1,758
  • 11
  • 14
  • 1
    This is not the reason. – Lightness Races in Orbit Aug 07 '15 at 11:00
  • The reason is, it has no reason to show an error, because there is no error – Michel Billaud Aug 07 '15 at 11:03
  • OP already stated that. You were supposed to explain *why* there is no error. – Mateusz Grzejek Aug 07 '15 at 11:05
  • There is no error because the code perfectly conforms to the rules of the language, and the compiler does its job properly. I see no point for discussion here. What can be explained is the rationale behind the standard of the language. A dull definition af the struct is not required, because is is not needed for a member which is "only" a pointer. – Michel Billaud Aug 07 '15 at 11:09
  • 1
    You need to explain, why `struct a { int e; abc* d; };` does not compile, although it meets your proposed (fantasy) rule set. – IInspectable Aug 07 '15 at 11:12
  • So your answer to "why is there no error reported?" is "because there is no error"? Wow, helpful. – Lightness Races in Orbit Aug 07 '15 at 11:13
  • _"A dull[sic] definition af[sic] the struct is not required, because is[sic] is not needed for a member which is 'only' a pointer."_ No, but a forward declaration _is_, and the OP is asking why it [seemingly] wasn't in this case. – Lightness Races in Orbit Aug 07 '15 at 11:13
  • Surroy about the typos : most of you have probably read "a full definition", and "it is not needed" "Full definition" means, precisely, "not a forward declaration". This is callled "incomplete type" in the standard, whiche states (3.9.2) « Pointers to incomplete types are allowed although there are restrictions on what can be done with them ». And no forward is required. – Michel Billaud Aug 07 '15 at 19:53
  • You are still missing the vital detail: Why is `struct abc*` and incomplete type, and `abc*` isn't? It's a reincarnation of my previous suggestion to explain, why `struct a { int e; abc* d; };` does **not** compile, even though it meets all your made-up requirements. – IInspectable Aug 10 '15 at 11:17
  • I'm afraid you're confusing "*incomplete type*" and "*unknown type name*'. **incomplete type** is a notion defined by the standard. See for example https://msdn.microsoft.com/en-us/library/200xfxh6.aspx << An "incomplete type" can be: - A structure type whose members you have not yet specified. - A union type whose members you have not yet specified. - An array type whose dimension you have not yet specified. >> . In "`abc*`", the name `abc` is an **unknown type name**. That's a different story. And it is ok to use a pointer to an inccomplete type – Michel Billaud Aug 10 '15 at 11:44
  • I'm afraid, you are confusing what you did write, and what you meant to write. Read your answer again. It explains, why `struct a { int e; abc* d; };` should compile, even though it doesn't. Unless your answer includes the information, that `struct abc*` is a pointer to an incomplete type, whereas `abc*` is a pointer to an unknown type, it doesn't address the question. Four downvotes seem to agree with this. – IInspectable Aug 10 '15 at 11:59
  • Maybe my answer didn't made clear enough that the type was "pointer to struct with unknown name", not the more general "pointer to unknown type" ? And, second point, `struct abc *d` actually contains a forward declaration of `abc` as a struct type. So the OP assertion "abc is used before declaration" is somehow incorrect. – Michel Billaud Aug 10 '15 at 13:37
  • The OP was **asking** a question. Your answer should address inaccuracies or wrong assumptions. It still doesn't, and you sill left out the most interesting piece of information: Contrasting `struct a { struct b* c; };` with `struct a { b* c; };`. You have been told, time upon time. I give up, sorry, I cannot remove the downvote. – IInspectable Aug 10 '15 at 16:34