1

Having the following C code:

struct Point2_s;
struct Point1_s{
  int x;
  int y;
  Point2_s P2;
} Point1;

struct Point2_s{
  int x;
  int y;
} ;


int main() {
    ...
    return 0;
}

I'm getting an error:

unknown type name ‘Point2_s’

Can anyone can please explain me WHY it doesn't work? Why doesn't the struct Point2_s declaration is insufficient when defining the Point1_s member P2?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
darro911
  • 136
  • 6
  • 2
    `Point2_s P2;` should be `struct Point2_s P2;`. If you want to be able to use the structure name without putting `struct` before it, use `typedef` to define an alias for it. – Barmar Feb 09 '23 at 23:16
  • 2
    It's not possible for the compiler to know the size of `Point2_s` without its definition. That's okay for pointers, but not for struct fields, which affect the outer struct's size and alignment. – alter_igel Feb 09 '23 at 23:18
  • OT: `Point2` contains xy for **one** point. `Point1` contains xy for **two** points... Is the point of this to confuse the reader? – Fe2O3 Feb 09 '23 at 23:23
  • In C, if you define a type `struct Foo`, its name is `struct Foo`, **not** `Foo`. You can use a typedef if you also want to call it `Foo`; I discussed this at some length [here](https://stackoverflow.com/a/26389105/827263). (In C++, if you define a type `struct Foo`, you can refer to it as `Foo`; C++ is a different language.) This is in addition to the issues about incomplete types that others have discussed. – Keith Thompson Feb 10 '23 at 02:47

3 Answers3

2

In this line

struct Point2_s;

there is declared an incomplete structure specifier struct Point2_s.

In this declaration

struct Point1_s{
  int x;
  int y;
  Point2_s P2;
} Point1;

there is used an unknown name Point2_s. It is not the same as struct Point2_s.

But even if you will write

struct Point1_s{
  int x;
  int y;
  struct Point2_s P2;
} Point1;

nevertheless you may not use an incomplete type in a data member declaration.

From the C Standard (6.7.2.1 Structure and union specifiers)

3 A structure or union shall not contain a member with incomplete or function type (hence, a structure shall not contain an instance of itself, but may contain a pointer to an instance of itself), except that the last member of a structure with more than one named member may have incomplete array type; such a structure (and any union containing, possibly recursively, a member that is such a structure) shall not be a member of a structure or an element of an array.

Instead you need to write

struct Point2_s{
  int x;
  int y;
} ;

struct Point1_s{
  int x;
  int y;
  struct Point2_s P2;
} Point1;

Or you could write

typedef struct Point2_s{
  int x;
  int y;
} Point2_s;

struct Point1_s{
  int x;
  int y;
  Point2_s P2;
} Point1;

In this case the name Point2_s is an alias for the type specifier struct Point2_s.

On the other hand, as it is pointed out in other answers you may use pointers to incomplete types because pointers themselves are always complete types. That is you may write

struct Point2_s;
struct Point1_s{
  int x;
  int y;
  struct Point2_s *P2;
} Point1;
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • So the same applies to the class'es in c++? Right? Am i right that so the declarations is NOT sufficient for custom data types like structs and/or classes because it can have various size but why is it sufficient for functions - one can ONLY have function declaration before function invocation? –  darro911 Feb 10 '23 at 00:03
  • @darro911 In C++ you may use structure names without the keyword struct. But in any case a data member shall be a complete type that is the size of an object of the type shall be known. – Vlad from Moscow Feb 10 '23 at 00:05
  • Ok I know that , but am I right that in case of functions the declaration is enought before the function call? –  darro911 Feb 10 '23 at 00:08
  • @darro911 Function parameters if it is not a function definition may be incomplete types. When for example a function parameter has an array type of unknown size the compiler adjusts it to pointer to the array element type as ant other array type.. – Vlad from Moscow Feb 10 '23 at 00:11
  • So to summarize: We CAN have function declarations BUT NOT struct/class? –  darro911 Feb 10 '23 at 00:39
  • 1
    @darro911: Function declarations are enough to reserve room for the call in the compiled code; it doesn't need the actual function until the linker gets involved. That's why they work, while forward declaration for `struct`s/`class`es of unknown size aren't enough to declare anything but a (fixed size) pointer to them (you can't even access the contents until the actual declaration has occurred). – ShadowRanger Feb 10 '23 at 00:47
  • @ShadowRanger Thx. That's the answer i expected - short and clear.:-) –  darro911 Feb 10 '23 at 00:50
2

A forward declaration can only be used to declare pointers to the forward-declared struct. It doesn't know how big it is though, so it can't use the type directly (how does it know how much space to reserve for the P2 member?).

Just reverse the order of declaration:

struct Point2_s{
  int x;
  int y;
};

struct Point1_s{
  int x;
  int y;
  struct Point2_s P2;  // You didn't typedef, so by the C standard, you need struct to declare the member
} Point1;

or you'll need to use pointers:

struct Point2_s;
struct Point1_s{
  int x;
  int y;
  struct Point2_s *P2; // Pointer, again adding struct; P2 will need to be allocated separately, e.g. by malloc
} Point1;

struct Point2_s{
  int x;
  int y;
};
ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
0

Forward declaration will not work in this case (abstracting from missing struct) as compiler needs to know the size of the member P2. You need to declare it before the the declaration which uses it.

struct Point2_s{
  int x;
  int y;
} ;

struct Point1_s{
  int x;
  int y;
  struct Point2_s P2;
} Point1;

Forward declaration will only work only for pointers:

struct Point2_s;

struct Point1_s{
  int x;
  int y;
  struct Point2_s *P2;
} Point1;

struct Point2_s{
  int x;
  int y;
} ;
0___________
  • 60,014
  • 4
  • 34
  • 74