I have the following code where a struct field depends on a struct field that is not declared yet, because that struct in turn might depend on the struct that I am trying to declare.
How can I design this so that it compiles? Or am I missing an obvious way to get rid of the union struct for keeping several struct definitions together?
typedef struct expression {
expression_type type;
union {
bool_expression bool;
identifier_expression ident;
integer_expression _int;
prefix_expression prefix;
infix_expression infix;
// TODO: Fix this
if_expression _if;
};
} expression;
typedef struct statement {
token token;
identifier name;
expression * value;
} statement;
typedef struct block_statement {
token token;
statement *statements;
} block_statement;
typedef struct if_expression {
token token;
expression condition;
block_statement *consequence;
block_statement *alternative;
} if_expression;
You can't, in this case.
if_expression contains an expression which in turn contains an if_expression. If you solve this problem by using pointers, you can reorder your definitions and use struct expression* to create a pointer to a struct that has not yet been defined.
You better remove the typedefs, at least initially, so you can better understand your types.
You should change your structs to point (rather than include) other structs, for example:
struct if_expression {
/* struct? */ token *token;
struct expression *condition;
struct block_statement *consequence;
struct block_statement *alternative;
}
Of course that will impose some judiciously use of malloc() and free() calls. In some cases you can later revert to inclusion (like token above, as it isn't expected that it points to your other structs, and copying tokens around is - perhaps - a cheap operation).
For the circularity of references you can forward declarations in C, that is you tell the compiler "hey, there is a struct named expression, whose internal structure you don't know yet, but bear with me, you will soon":
struct expression;
If you later decide to use typedef - so your code gets more streamlined - bear in mind that the structs can have a name, and typedefs define names, and those names don't share the same namespace. In examples:
typedef struct {
/* ...internal structure omited... */
} type_a;
typedef struct type_b {
/* ...internal structure omited... */
} type_b;
typedef struct struct_c {
/* ...internal structure omited... */
} type_c;
Here type_a is a type whose definition is an anonymous struct. And type_b is a type whose definition is struct type_b, that is a named (type_b) structure. And type_c is a type whose definition is struct struct_c, that is a named (struct_c) structure.
Now put it all together, you can:
/* forward all your structs */
struct expression;
struct if_expression;
struct block_statement;
/* typedef them all */
typedef struct expression expression;
typedef struct if_expression if_expression;
/* actually define them */
struct expression {
/* ... */
}
As a footnote, you can learn a lot about C language by understanding the difference between declaration and definition.
If you change expression condition; to expression *condition; in if_expression, and forward declare expression — typedef struct expression expression; at the top and then place struct expression { … }; at the bottom, the code should be OK.
/* Placeholder typedefs for undefined typedef names */
typedef int token;
typedef int identifier;
typedef int bool_expression;
typedef int identifier_expression;
typedef int integer_expression;
typedef int prefix_expression;
typedef int infix_expression;
typedef int expression_type;
/* The fixed code starts here */
typedef struct expression expression;
typedef struct statement
{
token token;
identifier name;
expression * value;
} statement;
typedef struct block_statement
{
token token;
statement *statements;
} block_statement;
typedef struct if_expression
{
token token;
expression *condition;
block_statement *consequence;
block_statement *alternative;
} if_expression;
struct expression
{
expression_type type;
union
{
bool_expression bool;
identifier_expression ident;
integer_expression _int;
prefix_expression prefix;
infix_expression infix;
if_expression _if;
};
};
expression expr = { 0 };
This compiles.
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;
#ifndef STAGE_TABLE_DEFINITION_HEADER
#define STAGE_TABLE_DEFINITION_HEADER
typedef stage_table_context_t* (*stage_table_function_t)(stage_table_context_t*);
typedef struct {
const char* stage_name;
stage_table_function_t* function;
} stage_t;
typedef struct {
uint32_t error_number;
stage_t* current_stage;
} stage_table_context_t;
#endif
Getting an unknown type error on stage_table_context_t.
The function pointer stage_table_function_t refers to stage_table_context_t and stage_table_context_t refers to stage_table_function_t.
Obviously positioning doesn't matter here since either orientation will result in an issue. Seems I need to forward declare the stage table context structure, but not sure how to do this with a typedef.
Apologies for the stupid question, I've been away from C for 6 months and I'm having a bit of a brain fart.
edit: Fixed some typo's in the code.
You can make the declaration of a struct before its definition:
/* declaration */
struct foo;
.....
/* definition */
struct foo
{
....
};
Anywhere you write struct foo is a declaration of the struct, so you don't have to put it in a separate line, you can have it in a typedef, pointer declaration, etc..
Just be aware that sometimes, like in variable declarations of type struct foo you also need the definition (to calculate the variable size);
/* declare struct foo ..*/
struct foo;
/* .. or declare struct foo ..*/
typedef struct foo foo;
/* .. or declare struct foo ..*/
struct foo *p;
/* .. or declare struct foo */
int bar (struct foo *p);
/* Not valid since we don't have definition yet */
struct foo f1;
/* definition */
struct foo
{
....
};
/* Valid */
struct foo f2;
In your case you haven't given the struct a name; you've just made a typedef that is an alias for an anonymous struct. So to forward declare your struct you have to give it a name:
/*
forward declare the `struct stage_table_context_t` and give it a typedef alias
with the same name as the structs name
*/
typedef struct stage_table_context_t stage_table_context_t;
typedef stage_table_context_t* (*stage_table_function_t)(stage_table_context_t*);
typedef struct {
const char* stage_name;
stage_table_function_t* function;
} stage_t;
struct stage_table_context_t{
uint32_t error_number;
stage_t* current_stage;
} stage_table_context_t;
You just have to tell the compiler that stage_table_context_t shall be a struct; by that, you implicitly forward-declare the struct stage_table_context_t, which's actual definition may then come later. Note that a typedef does not define a struct, it just introduces an alias. So the actual definition is struct stage_table_context_t { ..., regardless of whether you introduce an alias for it or not (and regardless of which name you use for the alias).
typedef struct stage_table_context_t* (*stage_table_function_t)(struct stage_table_context_t*);
typedef struct {
const char* stage_name;
stage_table_function_t* function;
} stage_t;
struct stage_table_context_t {
uint32_t error_number;
stage_t* current_stage;
};
// optional (if you want to use "stage_table_context_t" as an alias for "struct stage_table_context_t"):
typedef struct stage_table_context_t stage_table_context_t;
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;.
What's the difference between these two declarations in C:
typedef struct square{
//Some fields
};
and
typedef struct{
//Some fields
} square;
The first declaration:
typedef struct square {
// Some fields
};
defines a type named struct square. The typedef keyword is redundant (thanks to HolyBlackCat for pointing that out). It's equivalent to:
struct square {
//Some fields
};
(The fact that you can use the typedef keyword in a declaration without defining a type name is a glitch in C's syntax.)
This first declaration probably should have been:
typedef struct square {
// Some fields
} square;
The second declaration:
typedef struct {
// Some fields
} square;
defines an anonymous struct type and then gives it the alias square.
Remember that typedef by itself doesn't define a new type, only a new name for an existing type. In this case the typedef and the (anonymous) struct definition happen to be combined into a single declaration.
struct X { /* ... */ };
That create a new Type. So you can declare this new type by
struct X myvar = {...}
or
struct X *myvar = malloc(sizeof *myvar);
typdef is intended to name a type
typedef enum { false, true } boolean;
boolean b = true; /* Yeah, C ANSI doesn't provide false/true keyword */
So here, you renamed the enum to boolean.
So when you write
typedef struct X {
//some field
} X;
You rename the type struct X to X. When i said rename, it's more an other name.
Tips, you can simply write :
typedef struct {
//some field
} X;
But if you need a field with the same type (like in a linked list) you had to give a name to your struct
typedef struct X {
X *next; /* will not work */
struct X *next; /* ok */
} X;
Hope this helps :)
Edit :
As Keith Thompson said, typdef is intended to create alias :)
I am trying to define two structures in C when the second struct uses the first as an array member and has two pointer members of itself.
Visual Studio does not like my code:
syntax error : '}'
syntax error : identifier 'tokenListNode'
syntax error : missing '{' before '*'
any idea how to solve this?
--> Please note that the errors appear with or without the declarations I added at the beginning of the code.
--> In addition, if someone can explain to me what is the difference between the identifier
before and after the struct's curly brackets, I'll be grateful.
Below is the code:
#define ARRAY_SIZE 100
struct tokenListNode;
struct TOKEN_LIST_NODE;
enum TOKEN_TYPE
{
id = 0,
INT_NUM,
INT_REAL,
ASSIGNMENT_OP,
RELATION_OP,
ARITHMETIC_OP
} tokenType;
typedef struct TOKEN
{
char* lexema;
enum TOKEN_TYPE type;
int lineNumber;
} token;
typedef struct TOKEN_LIST_NODE
{
token tokenArray[ARRAY_SIZE];
tokenListNode* prevNode;
tokenListNode* nextNode;
int tokenCounter;
}tokenListNode;
You do not define tokenListNode until after you use it. Change to the following:
typedef struct TOKEN_LIST_NODE tokenListNode;
struct TOKEN_LIST_NODE
{
token tokenArray[ARRAY_SIZE];
tokenListNode* prevNode;
tokenListNode* nextNode;
int tokenCounter;
};
The definition of a structure is composed of the keyword struct; the "struct tag"; and the struct members
struct tag { int member1; /* &c */ };
You can leave the tag out and create an unnamed structure ... why you would do so is another matter: you can't refer to the structure without a struct tag!
struct { int member1; /* &c */ };
Also, you can take any type and give it another name using typedef
typedef old_type new_name;
as in
typedef struct tag { int member1; /* &c */ } tag;
/* <------------ old type ------------> <new name> */
The above line defines a struct (named struct tag) and, at the same time, gives that type a new name: tag
what is the difference between the identifier before and after the struct's curly brackets
That's the result of mixing definition of struct and typedef. The name before the {} is the "tag" of the structure, the name after the {} is the new name for the type being typedef'd.
You need to use the struct tag instead of it's typedef'ed version when referring to itself.
struct TOKEN_LIST_NODE
{
token tokenArray[ARRAY_SIZE];
struct TOKEN_LIST_NODE* prevNode;
struct TOKEN_LIST_NODE* nextNode;
int tokenCounter;
};