Forward Struct Declaration in C; not working - c

I read all the other posts with no success yet (eg forward declaration of a struct in C?)
There are two header files with functions which reference structs from each others' headers.
Forward declaration isn't working...surely because i'm still doing it incorrectly:) Thoughts?
foo.h:
typedef struct{
...
}foostruct;
extern foostruct fooStruct; //this struct used in foo.c and other c files
typedef struct barstruct; //attempt at forward declaration
void fooFctn(barstruct *barVar); //needs definition from bar.h
bar.h:
typedef struct{
...
}barstruct;
extern barstruct barStruct; //this struct used in bar.c and other c files
typedef struct foostruct; //attempt at forward declaration
void fooFctn(foostruct *fooVar); //needs definition from foo.h
The error is
error: useless storage class specifier in empty declaration [-Werror]
src/search.h:123:18: error: unknown type name 'foostruct'
Since these structs were typedef-d originally i also tried just "foostruct;" without the identifier which (of course) doesn't work, likewise declaring "typedef struct fooVar foostruct" generates a redefinition error.

In your foo.h, this code:
typedef struct barstruct;
is a degenerate typedef that announces that struct barstruct exists, but does not give an alternative name for it (hence the 'useless storage class specifier in empty declaration' warning/error). You need:
typedef struct barstruct barstruct;
Then the code will work properly in foo.h. The corresponding change is needed in bar.h for struct foostruct.
However, that still leaves you with a problem. The type barstruct declared in foo.h is not identical to the type barstruct declared in bar.h (because one is a tagged structure and one is a tagless structure). There are several ways around this. In C11 (but not C99 or C89), you can repeat a typedef if they're identical.
You would therefore have the two typedef lines:
typedef struct barstruct barstruct;
typedef struct foostruct foostruct;
at the top of the headers, and then define in bar.h:
struct barstruct { … };
and in foo.h:
struct foostruct { … };
If compatibility with earlier versions of C is important, then you need to consider using struct barstruct and struct foostruct in the function declarations:
foo.h
typedef struct foostruct foostruct;
struct foostruct
{
…
};
extern foostruct fooStruct;
struct barstruct;
void fooFctn(struct barstruct *barVar);
and analogously for bar.h. This will also work with C11, of course.

Properly typedef your struct should resolve your problem.
typedef struct foostruct foostruct;

Structures and tags
struct { ... }; is an anonymous structure. It is only useful with typedefs, and only when that typedef name is used and declared in that one file. In other words, it cannot be used with forward declarations.
However, struct X { ... }; is a structure of type struct X. It can be used for forward declarations. Note that X is just the tag name used to denote a specific structure type, not the actual type. The tag name is used to distinguish between other declared structure types. This confuses people sometimes, so an example might help. Note that all of the declared structure types are different:
/* Declare an anonymous structure. */
struct {
int n;
};
/* Another anonymous structure. It in different from the previous one. */
struct {
double d;
};
/* Declare a structure of type `struct bar'. */
struct bar {
int n;
};
/* Declare a structure of type `struct foo'. */
struct foo {
int n;
};
/* Declare a variable `var' of type `struct foo'. */
struct foo var;
/* Unless a typedef for the `foo' type exists, or a preprocessor macro is used to replace `foo' with an actual type, this is a compilation error. */
foo var2;
Note that if you attempt to declare two structures with the same tag name, it is an error.
typedefs
The form for a typedef is the same as for a variable declaration with no initializer:
typedef TYPE NAME;
For example:
typedef int Integer;
declares the Integer type to be the same as int. The same can be done with structures:
/* Typedef'd anonymous structure */
typedef struct {
int foo;
} fooBType;
/* Typedef'd `struct foostruct' structure */
typedef struct foostruct {
int foo;
} fooGType;
The difference between the two:
forward declarations of the structure type referenced by fooBType in other files are not possible because the structure referenced by fooBType is anonymous
forward declarations of the structure type struct foostruct referenced by fooGType are possible because the type is able to be referenced by the structure tag and the struct keyword, as in struct foostruct or typedef struct foostruct fooGType;
I hope this helps.

Related

Circular dependency in single C header file. Forward declaration needed?

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

structs in different headers refer to each other

I want to have a struct that contains a pointer to another struct which in turn has a function pointer with the function argument being a pointer to the first type of struct but I'm struggling to resolve the references. The struct definitions are in different header files and must be available to other code in the full project.
In a simplified example, in main I have:
#include "a.h"
typedef struct {
int x;
int (*func)(a_t * a);
int y;
} z_t;
In a.h:
#ifndef A_H_
#define A_H_
#include "z.h"
typedef struct {
int b;
int c;
z_t * z;
} a_t;
#endif /* A_H_ */
and in z.h:
#ifndef Z_H_
#define Z_H_
#include "a.h"
typedef struct {
int x;
int (*func)(a_t * a);
int y;
} z_t;
#endif /* Z_H_ */
I end up with circular #includes and type a_t is unknown in z.h
Can anyone help?
In C, you can have a circular reference among two or more structures, or from a structure to itself. Note that the reference can be by pointer only: one structure X cannot embed an instance of another while simultaneously X embeds an instance of Y. However, X can have a pointer to Y, while Y can point to X, or embed a copy of X.
The mechanism which allows a circular reference in C is the incomplete struct type. In C you can use struct in a declaration, without defining the body of the struct, like this:
struct foo *bar; // foo has never been seen before.
The foo identifier is the "struct tag". A later re-declaration of the same struct tag in the same scope which does include a body will complete the type:
struct foo { int member; }; // foo is now complete
With this we can do:
struct list_node {
struct list_node *next, *previous; // self reference
};
struct foo {
struct bar *bar_ptr;
};
struct bar {
struct foo *foo_ptr; // mutual references
};
In your code, you haven't used a single struct tag; all your struct types are anonymous, and you are relying on typedef aliases. The above referential tricks cannot be played out using typedef names; the struct tags are essential.
Only a struct which has a tag can be declared two or more times: incomplete the first times, and then completely. The declaration of a struct with no tag is anonymous; such a declaration invents a new, unique struct type each time it appears.

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

Using a struct in a header file "unknown type" error

I am using Kdevelop in Kubuntu.
I have declared a structure in my datasetup.h file:
#ifndef A_H
#define A_H
struct georeg_val {
int p;
double h;
double hfov;
double vfov;
};
#endif
Now when I use it in my main.c file
int main()
{
georeg_val gval;
read_data(gval); //this is in a .cpp file
}
I get the following error:
georeg_chain.c:7:3: error: unknown type name 'georeg_val'
(This is in the georeg_val gval; line)
I would appreciate if anyone could help me resolve this error.
In C one has two possibilities to declare structure:
struct STRUCT_NAME {} ;
or
typedef struct {} STRUCT_ALIAS;
If you use first method (give struct a name) - you must define variable by marking it explicitly being a struct:
struct STRUCT_NAME myStruct;
However if you use second method (give struct an alias) then you can omit struct identifier - compiler can deduce type of variable given only it's alias :
STRUCT_ALIAS myStruct;
Bonus points:
You can declare struct with both it's name and alias:
typedef struct STRUCT_TAG {} STRUCT_TAG;
// here STRUCT_NAME == STRUCT_ALIAS
Then in variable definition you can use either first or second method. Why both of two worlds is good ? Struct alias lets you to make struct variable definitions shorter - which is a good thing sometimes. But struct name let's you to make forward declarations. Which is indispensable tool in some cases - consider you have circular references between structs:
struct A {
struct B * b;
}
struct B {
struct A * a;
}
Besides that this architecture may be flawed - this circular definition will compile when structs are declared in the first way (with names) AND struct pointers are referenced explicitly by marking them as struct.
If you have to define a new type, you have to write:
typedef struct {
int p;
double h;
double hfov;
double vfov;
} georeg_val ;
Then you can use georeg_val as a new type.
Defining a struct type (on this example, a binary search tree struct):
struct tree {
int info;
struct tree *left;
struct tree *right;
}
typedef struct tree treeNode;
Declaring a function eg.:
treeNode *insertElement(treeNode *treeA, int number);

using C struct that is declared later

I want use a typedef struct that isn't already defined, but it is later.
Is there anything like a struct prototype?
file container.h
// i would place a sort of struct prototype here
typedef struct
{
TheType * the_type;
} Container;
file thetype.h
typedef struct {......} TheType;
file main.c
#include "container.h"
#include "thetype.h"
...
Replace this line:
// i would place a sort of struct prototype here
with these lines:
struct TheType;
typedef struct TheType TheType;
Since you need the type TheType to be defined before type Container is defined, you have to use forward declaration of type TheType - and to do so you also need forward declaration of struct TheType.
Then you will not define typedef TheType like this:
typedef struct {......} TheType;
but you will define struct TheType:
struct {......};
In container.h:
struct _TheType;
typedef struct _TheType TheType;
Than in thetype.h:
struct _TheType { ..... };
You can declare a struct inside the typedef:
typedef struct TheType_Struct TheType; // declares "struct TheType_Struct"
// and makes typedef
typedef struct
{
TheType * p;
} UsefulType;
Note though that you may only have at most one typedef in one translation unit in C89 and C99 (this differs from C11 and C++).
Later on you must define the actual struct TheType_Struct { /* ... */ }.
You cannot define an object of an, as yet, undefined struct; but you can define a pointer to such a struct
struct one {
struct undefined *ok;
// struct undefined obj; /* error */
};
int foo(void) {
volatile struct one obj;
obj.ok = 0; /* NULL, but <stddef.h> not included, so 0 */
if (obj.ok) return 1;
return 0;
}
The above module is legal (and compiles with gcc without warnings).

Resources