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};
Related
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;
I'm working on a problem involving the code below, and I'm a bit lost.
What is "class[]" doing, and how does that change how I would print the members? I've never seen an initialization like this before.
int main(){
struct Student {
char Initials2[2];
int id;
struct Student *teammate;
};
typedef struct Student SType;
#define XYpt &class[0]
#define ABpt &class[1]
#define RSpt &class[2]
#define CDpt &class[3]
#define JVpt &class[4]
#define RYpt &class[5]
SType class[6] = {
{{'X','Y'},123, RSpt},
{{'A','B'},23, RYpt},
{{'R','S'},11, XYpt},
{{'C','D'},44, JVpt},
{{'J','V'},42, CDpt},
{{'R','Y'},457, ABpt}
};
return 0;
}
What the code does:
struct Student is a bit special, as it is containing a pointer to an object of the same type struct Student *teammate. This is possible by using a pointer to an object with the "struct tag" Student, which acts as a form of forward declaration.
typedef struct Student SType; just hides away the struct keyword, which is a coding style matter. It would have been cleaner to write the whole thing like this:
typedef struct Student {
char Initials2[2];
int id;
struct Student *teammate;
} SType;
SType class[6] = { {{'X','Y'},123, RSpt}, .... is just an array of 6 structs, each initialized. The bunch of macros expand to variable addresses of the same array named "class". This is poor style - the programmer used this as a dirty way to "name" each item in the array. The postfix "pt" seems to mean pointer.
How the code could have been written:
Rather than using ugly macros, it is possible to associate each item of an array with an identifier, by using a union. For example:
typedef union
{
struct foo
{
int foo;
int bar;
} foo;
int array [2];
} foobar;
Here, an object foobar fb; can be accessed as fb.foo.foo or fb.array[0] and it means the same item 0 of the array. With modern standard C, we can drop the inner struct name (anonymous struct) and just access the objects as fb.foo.
Also, this can be combined with designated initializers to initialized certain named members of the struct by their name: foobar fb { .foo = 1, .bar = 2 };.
Rewriting your example by using unions, anonymous struct and designated initializers, we get this instead:
typedef struct student {
char initials [2];
int id;
struct student *teammate;
} s_type;
typedef union
{
struct
{
s_type XY;
s_type AB;
s_type RS;
s_type CD;
s_type JV;
s_type RY;
};
s_type array [6];
} class_t;
class_t class =
{
.XY = { .initials={'X','Y'}, .id=123, .teammate = &class.RS},
.AB = { .initials={'A','B'}, .id= 23, .teammate = &class.RY},
.RS = { .initials={'R','S'}, .id= 11, .teammate = &class.XY},
.CD = { .initials={'C','D'}, .id= 44, .teammate = &class.JV},
.JV = { .initials={'J','V'}, .id= 42, .teammate = &class.CD},
.RY = { .initials={'R','Y'}, .id=457, .teammate = &class.AB},
};
This is much easier to read and understand. Plus we can still use it as an array with class.array[i] if we want.
I would like to forward declare a typedef struct, to use it in another struct, and then to implement the original struct.
I have tried the following code but does not compile.
struct _s1;
struct _s2;
typedef struct _s1 s1;
typedef struct _s2 s2;
typedef struct _big_struct {
s1 my_s1;
s2 my_s2;
} big_struct;
struct _s1 {
int i1;
};
struct _s2{
int i2;
};
Any idea?
You can only forward declare the existence of a type and then use a pointer to it. This is because the size of a pointer is always known, while the size of a forward declared compund type is not, yet.
struct s1;
struct s2;
struct big_struct {
struct s1* pmy_s1;
struct s2* pmy_s2;
};
struct s1 {
int i1;
};
struct s2{
int i2;
};
Note, because of my background, I am used to writing extremely backward-compatible code.
Jonathan Leffler has provided information on need/not-need in more modern versions of the C standard. See the comments below.
If you are really forced with that order (I don't care why), one thing that comes in my mind to have it compile is by making the struct _big_struct entries pointers:
typedef struct s1 s1;
typedef struct s2 s2;
typedef struct _big_struct {
s1 *my_s1;
s2 *my_s2;
} big_struct;
Can anyone explain me what is the difference between this:
typedef struct{
char a[10];
int b;
char c[8];
...
}test;
and this:
typedef struct test{
char a[10];
int b;
char c[8];
...
}test;
Thanks
typedef struct{
char a[10];
int b;
char c[8];
...
}test;
The above defines an anonymous struct and immediately typedefs it to the type alias test.
typedef struct test{
char a[10];
int b;
char c[8];
...
}test;
This however, creates a struct named struct test as well as adding a typedef for it.
In the first case, you will not be able to forward declare the struct if you need to.
There's also a philosophy (which I happen to agree with to a point), that typedefing all structures by default makes code less readable, and should be avoided.
Having "test" in two different places is a bit confusing. I usually write code like this:
typedef struct test_s {
...
} test;
Now I can either use type struct test_s or just test. While test alone is usually enough (and you don't need test_s in this case), you can't forward-declare pointer to it:
// test *pointer; // this won't work
struct test_s *pointer; // works fine
typedef struct test_s {
...
} test;
With the first version you can only declare:
test t;
With the second versijon you can choose between:
struct test t;
test t;
Short answer: They're the same (in your code)
Long answer: Why put test between typedef struct and {? Is that pointless?
This (struct name test) is pointless in your code
In this code however, it's not:
struct Node {
int data;
struct Node * next;
} head;
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;