Struct declaration NOT sufficient? - c

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?

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;

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;
};

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;
} ;

Related

What is the difference when defining structs with typedef?

Option 1:
typedef struct s{
int x;
double y;
char z;
}mystruct;
Option 2:
typedef struct {
int x;
double y;
char z;
}mystruct;
What's the difference between these 2 options?
With option 1 you can declare a variable like this:
struct s foo;
or
mystruct foo;
With option 2 the only possibility is:
mystruct foo;

Clarification about a particular struct definition in C

I found this structure in the slides of my professor:
struct point{
int x;
int y;
} p;
What does p mean? So far I used only the classical struct like this:
struct point{
int x;
int y;
};
struct point{
int x;
int y;
} p;
defines a variable p of type struct point
it is same as
struct point{
int x;
int y;
};
struct point p;
struct point{
int a;
int b;
}p;
This is the same as using struct point p
When we use typedef struct p as in
typedef struct point{
int a;
int b;
}p;
We can use p to declare a structure pointer or structure variable later on
To create a structure pointer p *abc
To create a structure variable p xyz

"struct" before already-declared struct

I am still new in C. I know you can just use the already-declared struct as new data type such as int, double, etc. However, I encounter a struct written like this:
struct AdjListNode
{
int dest;
int weight;
struct AdjListNode* next;
};
In this struct, the data type of "next" pointer is struct AdjListNode*. What does struct have to do with the already-declared AdjListNode*? Thanks!
What does struct have to do with the already-declared AdjListNode*?
The answer is that the c syntax requires it.
You do not get a type AdjListNode by writing struct AdjListNode { ... };
AdjListNode is a struct tag and you always have to use struct AdjListNode when declaring variables.
See this simple example (without pointer inside the struct):
#include <stdio.h>
struct sSomeName
{
int x;
};
int main(void) {
struct sSomeName var; // OK, variable of type struct sSomeName
struct sSomeName* pVar; // OK, pointer to variable of type struct sSomeName
// sSomeName var2; // ERROR: unknown type name 'sSomeName'
var.x = 5;
pVar = &var;
printf("%d\n", pVar->x);
return 0;
}
So if you want to add a pointer inside the struct, you must write struct sSomeName just as you have to do inside main, i.e. like:
struct sSomeName
{
int x;
struct sSomeName* p;
};
Using typedef
If you want a type named AdjListNode you must use typedef.
A typedef example could look like:
#include <stdio.h>
typedef struct sSomeName sSomeName;
struct sSomeName
{
int x;
sSomeName* p;
};
int main(void) {
sSomeName var;
sSomeName* pVar;
var.x = 5;
var.p = NULL;
pVar = &var;
printf("%d\n", pVar->x);
printf("%p\n", (void*)pVar->p);
return 0;
}
Here with that declaration pointer to structure is declared. This is basically used for implementing linked list or for other data structures like tree.
It does'nt mean that struct is re-declared. It is similar to declare a struct variable.
The structure is created as follows: typedef struct AdjListNode. Example:
#include <stdio.h>
#include <stdlib.h>
typedef struct AdjListNode
{
int dest;
int weight;
struct AdjListNode* next;
}AdjListNode;
typedef struct Nodo{
char *nombre;
int *edad;
struct Nodo *siguiente;
}Nodo;
int main(int argc, char **argv) {
AdjListNode *nodo=malloc(sizeof(AdjListNode));
nodo->dest=1;
nodo->weight=2;
nodo->next=NULL;
printf("Nodo-->dest: %d", nodo->dest);
free(nodo);
}

error: dereferencing pointer to incomplete type

Looked through many other SO posts related to this, but none were able to help me. So, I have the following structs defined:
typedef struct
{
int created;
double data;
int timeLeft;
int destination;
}dataPacket;
typedef struct
{
dataPacket *array;
int currIndex;
int firstIndex;
int nextTick;
int maxLength;
int length;
int stime;
int total;
}packetBuffer;
typedef struct{
int mac;
struct wire *lconnection;
struct wire *rconnection;
int numRecieved;
struct packetBuffer *buffer;
int i;
int backoff;
}node;
typedef struct{
float length;
float speed;
int busy;
struct dataPacket *currPacket;
struct node *lnode;
struct node *rnode;
}wire;
And then I'm trying to use the following function:
int sendPacket(node *n, int tick)
{
if(n->buffer->length > 0)
{
if(n->backoff <= 0)
{
if (n->lconnection->busy != 0 || n->lconnection->busy != 0)
{
n->i++;
n->backoff = (512/W * genrand()*(pow(2,n->i)-1))/TICK_LENGTH;
}
else
{
n->lconnection->busy = 1;
n->rconnection->busy = 1;
n->lconnection->currPacket = n->buffer[n->buffer->currIndex];
n->rconnection->currPacket = n->buffer[n->buffer->currIndex];
}
}
else
{
n->backoff--;
}
}
}
I'm getting the error described in the title everytime I try to access a member of buffer, lconnection, or rconnection.
struct packetBuffer *buffer;
You've defined a type packetBuffer (a typedef for an otherwise anonymous struct).
You haven't defined struct packetBuffer.
In the absence of an existing type struct packetBuffer, the compiler treats it as an incomplete type, assuming that you'll complete it later. The declaration
struct packetBuffer *buffer;
is perfectly legal, but you can't dereference buffer unless the type struct packetBuffer is visible.
Just drop the struct keyword.
(My personal preference is to drop the typedef and consistently refer to struct types as struct whatever, but that's a matter of style and taste.)
The following:
typedef struct {
int x;
char *y;
...
} my_struct;
creates an identifier for an anonymous structure. In order, for a structure to refer to an instance of itself, it must not be "anonymous":
typedef struct my_struct {
int x;
char *y;
struct my_struct *link
....
} my_struct_t;
This means that my_struct_t is now the type struct my_struct and not just an anonymous struct. Also, note that struct my_struct can be used within its own structure definition. That is not possible with anonymous structs.
As a final complication, the my_struct in struct my_struct is in a differenct "namespace" than the my_struct_t. This is sometimes used to to simplify (or confuse) things in code like this:
typedef struct my_struct {
int x;
char *y;
struct my_struct *link
....
} my_struct;
Now I can use my_struct anywhere in my code instead of struct my_struct.
Finally, you could separate the typedef from the structure definition to achieve the same effect:
struct my_struct {
int x;
char *y;
struct my_struct *link;
....
};
typedef struct my_struct my_struct;
As noted in David R.Hanson's C Interfaces and Implementations, "This definition is legal because structure, union, and enumeration tags occupy a same name space that is separate from the space for variables, functions, and type names."

C typedef function prototype with struct attempting to reference before defined.

I need to reference a struct that's not yet defined because the struct actually conatins the typedef'd function prototype.
For example,
typedef int (MyCallbackFunction)(X * x, void * ctx);
typedef struct CallbackData {
MyCallbackFunction * callback;
void * ctx;
} CallbackData;
typedef struct X {
char a;
int b;
int c;
double d;
CallbackData e;
} X;
What's the valid way to actually write this code/header ?
Just forward declare the relevant types - and you can make the function pointer part of the typedef:
struct X_;
typedef int (*MyCallbackFunction)(struct X_ * x, void * ctx);
typedef struct CallbackData_ {
MyCallbackFunction callback;
void * ctx;
} CallbackData;
typedef struct X_ {
char a;
int b;
int c;
double d;
CallbackData e;
} X;
Just forward declare your typedefs
typedef struct X X;
typedef struct CallbackData CallbackData;
and then declare the structs later.
Yes, you can forward declare the struct and use it in the declaration of MyCallbackFunction where you don't need it to be a complete type.
struct X;
typedef int (MyCallbackFunction)(struct X * x, void * ctx);

Resources