Resolve circular typedef dependency? - c

What is the best way to resolve the following circular dependency in typedef-ing these structs?
Note the C language tag - I'm looking for a solution in standard gcc C.
typedef struct {
char* name;
int age;
int lefthanded;
People* friends;
} Person;
typedef struct {
int count;
int max;
Person* data;
} People;

The answer lies in the difference between declaration and definition. You are attempting to declare and define in the same step (in the case of a new type via typedef). You need to break these up into different steps so the compiler knows what you are talking about in advance.
typedef struct Person Person;
typedef struct People People;
struct Person {
char* name;
int age;
int lefthanded;
People* friends;
};
struct People {
int count;
int max;
Person* data;
};
Note the addition of the two 'empty' typedefs at the top (declarations). This tells the compiler that the new type Person is of type 'struct Person' so that when it sees that inside the definition of struct People it knows what it means.
In your particular case, you could actually get away with only predeclaring the People typdef because that is the only type used before it is defined. By the time you get into the definition of struct People, you have already fully defined the type Person. So the following would also work but is NOT RECOMMENDED because it is fragile:
typedef struct People People;
typedef struct {
char* name;
int age;
int lefthanded;
People* friends;
} Person;
struct People {
int count;
int max;
Person* data;
};
If you swap the order of the structure definitions (moving struct People above the typedef of Person) it will fail again. That's what makes this fragile and, therefore, not recommended.
Note that this trick does NOT work if you include a struct of the specified type rather than a pointer to it. So, for example, the following WILL NOT compile:
typedef struct Bar Bar;
struct Foo
{
Bar bar;
};
struct Bar
{
int i;
};
The above code gives a compiler error because the type Bar is incomplete when it tries to use it inside the definition of struct Foo. In other words, it doesn't know how much space to allocate to structure member 'bar' because it hasn't seen the definition of struct bar at that point.
This code will compile:
typedef struct Foo Foo;
typedef struct Bar Bar;
typedef struct FooBar FooBar;
struct Foo
{
Bar *bar;
};
struct Bar
{
Foo *foo;
};
struct FooBar
{
Foo foo;
Bar bar;
FooBar *foobar;
};
This works, even with the circular pointers inside Foo and Bar, because the types 'Foo' and 'Bar' have been pre-declared (but not yet defined) so the compiler can build a pointer to them.
By the time we get to defining FooBar, we have defined how big both Foo and Bar are so we can include the actual objects there. We can also include a self-referential pointer to type FooBar because we have pre-declared the type.
Note that if you moved the definition of struct FooBar above the definitions of either struct Foo or Bar, it would not compile for the same reason as the previous example (incomplete type).

Forward-declare one of the structs:
struct people;
typedef struct {
/* same as before */
struct people* friends;
} Person;
typedef struct people {
/* same as before */
} People;

As for readability :
typedef struct Foo_ Foo;
typedef struct Bar_ Bar;
struct Foo_ {
Bar *bar;
};
struct Bar_ {
Foo *foo;
};
It might be a good idea to avoid typedef struct altogether;

Since Person just wants a pointer to People, it should be fine to just predeclare the latter:
typedef struct People People;
Then change the second declaration to just declare using the struct tag, like so:
struct People {
int count;
int max;
Person data[];
};

struct _People;
typedef struct {
char* name;
int age;
int lefthanded;
struct _People* friends;
} Person;
struct _People {
int count;
int max;
Person data[1];
};
Note: Is Person data[]; standard?

struct People_struct;
typedef struct {
char* name;
int age;
int lefthanded;
struct People_struct* friends;
} Person;
typedef struct People_struct {
int count;
int max;
Person data[];
} People;

Related

How to define a typedef struct inside another one with anonymous union? [duplicate]

This question already has answers here:
What is 'forward declaration' and the difference between 'typedef struct X' and 'struct X'?
(5 answers)
Closed 3 years ago.
I want to represent a nested ast node
typedef struct ast_assignment
{
char* sym;
ast_node* value;
} ast_assignment;
typedef struct ast_conjunction
{
char* sym;
ast_node* value;
} ast_conjunction;
typedef struct ast_node {
int node_type;
union {
ast_assignment data;
ast_conjunction data;
};
} ast_node;
but no matter what I define first, the compiler tells me that the other struct is an unknown type? How to proceed?
Typedef has to describe an actual type name
Typedefs require a ; after them
Circular type references require a bit of special sauce
Unions require different member names
Might you mean:
struct ast_node; // forward declaration
typedef struct {
char* sym;
struct ast_node* value;
} ast_assignment;
typedef struct ast_conjunction {
char * sym;
struct ast_node* value;
} ast_conjunction;
typedef struct ast_node {
int node_type;
union {
ast_assignment data_asg;
ast_conjunction data_conj;
};
} ast_node;
Expanding on this a bit for a more complete answer.
First, the purpose of a typedef is to install a new name into the compiler that you can use, so typedef struct { ... }; doesn't really do much. It should be typedef struct {...} newtype; so you can use that actual name newtype.
It also requires a semicolon after, which messes me up every time I go back from C# to C :-)
The circular reference thing is tricky, and doing struct mytype; in advance means you can use that name mytype only if it's in a context where knowledge of the structure details don't have to be known. In practice, it means you can use the struct mytype * as a pointer - because this is a fixed size - but this is not allowed:
struct ast_node; // forward declaration
struct some_other_type {
struct ast_node *nodeptr; // this is ok
struct ast_node thisnode; // FAIL
...
};
The reason is: a pointer is a fixed size no matter what kind of data it points to so the compiler carries you a bit, but the thisnode would require knowledge of all the details. Sorry, no way to do that.
Re: the union, you can't define any union or struct with two members with the same name because how could you reference one of them and the compiler would know which?
Personally I'm not a fan of using typedef for structure types, so I'd do this as:
struct ast_node; // forward struct defn
struct asg_assignment {
char *sym;
struct ast_node *value;
};
struct ast_conjunction {
char * sym;
struct ast_node* value;
};
struct ast_node {
int node_type;
union {
struct ast_assignment data_asg;
struct ast_conjunction data_conj;
};
};
... but I'm not sure I can justify this by anything other than personal preference.
You have multiple errors in your code. The correct way to declare a struct is as follows:
struct a {
...
}; // needs a semicolon
And to refer to it, you must use the struct keyword as well;
struct b {
struct a data;
};
In your case, the proper code that will compile is:
struct ast_assignment
{
char* sym;
struct ast_node* value;
};
struct ast_conjunction
{
char* sym;
struct ast_node* value;
};
struct ast_node {
int node_type;
union {
struct ast_assignment data_assignment;
struct ast_conjunction data_conjunction; // you cannot have multiple members with the same name
};
};
In C, the type you want to caöl has to be declared first.
However, you can just use another pointer like void*.
void* is a pointer that can be used for any type.
If you define type of the later struct in the first struct as void*, the compiler will allow it.
But this has drawbacks. You are losing type safety with this and you may need to cast at some points.
Also, a typedef shortcut does not allow it to be used before the whole the typedef is declared.
This means, you can't use the shortcut inside the struct.
For example, the following would not be possible:
typedef struct mystruct{
myStruct_t *myValue;
} myStruct_t;
You'll need to do this instead:
typedef struct mystruct{
struct myStruct *myValue;
} myStruct_t;

Visual C 2012: I am getting weird errors. Code Segment and Error provided

I am writing a game in C. But I keep getting a number of errors. One prominent one is this. "Illegal Identifier: X" where X is the type of a variable inside a structure. An instance, Illegal Identifier: MapItem, is caused by the following code
typedef struct MapItem{
int item;
int count;
};
typedef struct MapTile{
MapItem item;
int x;
int y;
int tile;
Direction dir;
int drop;
};
The error is attached to the first line inside the MapTile struct. I would like to know why this error is occurring, and how to fix it.
The code segment was taken, in exact order, from map.h. Direction is an enum declared earlier in the same header.
Thank you all for answering. However, I did receive the answer I needed 4 hours ago.
Your typedef are incorrect. The syntax is:
typedef type typealias ;
So:
typedef struct
{
int item;
int count;
} MapItem;
typedef struct
{
MapItem item;
int x;
int y;
int tile;
Direction dir;
int drop;
} MapTile;
Note that types being aliased here are anonymous structs, the struct-tag is only required for self-referencing structs.
typedef is used to create an alias to another type (existing or defined in the same typedef statement).
Its general format is:
typedef existing_or_new_type alias;
The aliased type in your typedef is the new struct MapItem defined in the typedef statement but the alias is missing. This is the cause of the error.
You can use:
typedef struct MapItem {
int item;
int count;
} MapItem;
This statement declares the new type struct MapItem (the struct keyword is part of the type name) and the new type MapItem that is an alias of struct MapItem. This means that everywhere you can or have to use struct MapItem you can use MapItem instead.
If this seems confusing, you can use different names for the struct type and its alias. Or you can omit the name from the struct definition at all:
typedef struct {
int item;
int count;
} MapItem;
This way, MapItem is the name of an anonymous struct type and it is the only way to declare variables of this type.

Initialize typedef struct

Why does this work:
struct person {
char name[50];
short mental_age;
} p1 = {"Donald", 4};
But not this:
typedef struct {
char name[50];
short mental_age;
} PERSON p1 = {"Donald", 4};
Is there a way that I can make a typedef struct and initialize Donald when I define this struct?
typedefs are aliases for other types. What you're doing is creating a convenience typedef. Since the purpose of a typedef is to create type aliases, you can't define a variable using it.
You have to do this:
typedef struct {
// data
} mytype;
mytype mydata = {"Donald", 4};
The best way, that I know of, is to separate the strict definition from the typedef statement from the struct declaration, similar to:
struct sPerson
{
char name[50];
short mental_age;
};
typedef struct sPerson PERSON;
PERSON p1 = {"Donald", 4};

Is a struct {...}; a type or an unnamed variable?

Is the following, at file scope, a type declaration or an unnamed variable?
struct student_s {
char* name;
int age;
double height;
struct student_s* next;
};
If it is a type definition, then what is the difference with:
typedef struct student_s {
char* name;
int age;
double height;
struct student_s* next;
};
?
(Background: see my answer at Changing a variable from global to local - C, where I believe the first introduces an unnamed variable that is then optimized away by the compiler.)
Note: the question has been flagged as a possible duplicate of In what scope is a struct member identifier put? but I believe I am not asking a question about the scope of the members but about what the declarations actually create. However. answers to Difference between 'struct' and 'typedef struct' in C++? do explain my question.
As per the C standard, a structure declaration in the form like
struct student_s {
char* name;
int age;
double height;
struct student_s* next;
};
is the declaration of a type. Quoting C11, chapter §6.7.2.1
The presence of a struct-declaration-list in a struct-or-union-specifier declares a new type, within a translation unit. The struct-declaration-list is a sequence of declarations for the members of the structure or union. [...]
C standard does not mandate creating a variable (either named or unnamed) for that type.
In your second snippet, you actually (try to) typedef to nothing. However, if you change your snippet to the form of
typedef struct {
//.....members
} student_s ;
you'll be creating a type student_s (typedef to an unnamed structure type) which you can use later.
FWIW, we never talked about a variable being created here, anyways. It's all about types.
First declaration declares a type. After that declaration, the type struct student_s is known, and you can declare variables of that type or pointer to it :
struct student_s student1;
struct student_s *pStudent;
The second declaration is weird even if is compiles. The common usage would be :
typedef struct {
char* name;
int age;
double height;
struct student_s* next;
} studend_t;
which declares an alias student_t to an anonymous struct. It can then be used directly :
student_t student1;
student_t *pStudent;
BUT THE SECOND EXAMPLE DOES COMPILE (even with a warning) AND IS THE SAME AS FIRST ONE !
What it really does is to declare a void alias to struct student_s. The typedef is ignored and produces a warning : typedef requires a name, but as a side effect, the struct is declared, exactly as it was in first example.
So the true answer to the actual question is THERE ARE NO DIFFERENCES except for a warning.
Both are type definitions. The second one is one incomplete. It doesn't supply a name as the the argument of typedef. Much better is to use
typedef struct student_s {
char* name;
int age;
double height;
struct student_s* next;
} student;
Regarding the legality of
typedef struct student_s {
char* name;
int age;
double height;
struct student_s* next;
};
I've asked that as a separate question, Legality of `typedef struct foo {int bar};`
It's a type, and you can't have an anonymous instance of a struct. For comparison, this declares both the type struct_type and an instance struct_instance of that type:
struct struct_type {
/* blah */
} struct_instance;
If you wanted to declare another instance in isolation (from the type decl) you'd use
struct struct_type another_instance;
The use of typedef - if done correctly, unlike your example - just allows you to give the type another name which doesn't require the struct keyword to declare an instance:
typedef struct_type MyStruct;
MyStruct yet_another_instance;
or equivalently
typedef struct struct_type {
/* blah */
} MyStruct;
omitting the name (struct_type) gives you an anonymous struct type which can only referred to by its typedef'd name.
Note 1
Since your original struct contains a next pointer to its own type, that type must have a name at the point the member is declared. So, you cannot declare an anonymous struct with a self-typed pointer. If you give your anonymous struct type a name with typedef, that name doesn't exist until after the member declaration, so can't be used there.
typedef struct /*S*/ {
struct S *next; /* T doesn't exist yet, so without S, you can't declare this */
} T;
Note 2
You can declare an anonymous instance of an anonymous union, as a member:
struct S {
union {
int i;
unsigned u;
};
};
struct S s;
s.i = -1;
printf("%x\n", s.u);
but that's a very special case. I took the remark about this out of the main argument, in case it was misleading.
struct A { ... }
creates struct 'A' visible in struct namespace (which has nothing common with C++ namespaces). So, to access struct you have to use struct keyword;
struct A a;
When defined with typedef struct
typedef struct A { ... } B;
becomes visible and bound to B, and you can easily create struct like common variable of type B
B a;
Please, correct me someone, if I am wrong.
The difference is that with the first example, you have to declare a new variable like this: struct student_s variable;, however with the second example, you may simply do student_s variable;.

C: pointer to struct in the struct definition

How can I have a pointer to the next struct in the definition of this struct:
typedef struct A {
int a;
int b;
A* next;
} A;
this is how I first wrote it but it does not work.
You can define the typedef and forward declare the struct first in one statement, and then define the struct in a subsequent definition.
typedef struct A A;
struct A
{
int a;
int b;
A* next;
};
Edit: As others have mentioned, without the forward declaration the struct name is still valid inside the struct definition (i.e. you can used struct A), but the typedef is not available until after the typedef definition is complete (so using just A wouldn't be valid). This may not matter too much with just one pointer member, but if you have a complex data structure with lots of self-type pointers, may be less wieldy.
In addition to the first answer, without a typedef and forward declaration, this should be fine too.
struct A
{
int a;
int b;
struct A *next;
};
You are missing the struct before the A*
typedef struct A {
int a;
int b;
struct A* next;
} A;
You can go without forward declaration:
struct A {
int a;
int b;
struct A *next;
};
Please, you're in C, not C++.
If you really must typedef a struct (and most programmers that I work with would not¹), do this:
typedef struct _A {
int a;
int b;
struct _A *next;
} A;
to clearly differentiate between _A (in the struct namespace) and A (in the type namespace).
¹typedef hides the size and storage of the type it points to ― the argument (and I agree) is that in a low-level language like C, trying to hide anything is harmful and counterproductive. Get used to typing struct A whenever you mean struct A.
typedef struct {
values
} NAME;
This is shorter way to typedef a struct i think its the easiest notation, just don't put the name infront but behind.
you can then call it like
NAME n;
NAME *n; // if you'd like a ptr to it.
Anything wrong with this approach?

Resources