I want to hide the struct define, so I define struct in the source file, like this :
//a.c
#include "a.h"
struct a_s
{
int a;
int b;
};
int func(a_t *a)
{
printf("%d\n", a->a);
return 0;
}
and I declare the struct in the header file, like this:
//a.h
#ifndef TEST
#define TEST
#include <stdio.h>
#include <stddef.h>
typedef struct a_s a_t;
#endif
Then I use the struct a_t int main.c file, like this:
#include "stddef.h"
#include "a.h"
int main()
{
a_t a;
a.a =2;
func(&a);
return 0;
}
But when I compile the main.c by gcc -c main.c, it failed by
main.c: In function ‘main’:
main.c:7:15: error: storage size of ‘a’ isn’t known
struct a_s a;
Why is this failing?
if you want to hide the struct define, The user can only define the pointer of the type, and you must implement a api that create the struct instance(by malloc) and a api that release the struct instance(by free)
If you instantiate an object A a, the linker searches for the definition of A in order for the compiler to know how much memory it needs to allocate. It searches a.h and finds a typedef but no declaration, and so the error is saying that it doesn't know A's size.
If the purpose of the program is to hide the declarations (and definitions) from the users, you will need to use A *a, as this says to the compiler "there is a type A, and memory for it will be stored beginning at this memory location" and so doesn't need any information about the size or layout of the data until runtime where memory should be dynamically allocated and freed.
This approach allows the developers to expose an interface to users, without the users knowing any specifics on how data is structured and allowing the software to be updated and data structures modified all while keeping the outward facing headers the same (and keeping tests passing).
You can't create an instance of a struct that hasn't been defined because the compiler doesn't know how much space to allocate for it.
You can't access the members of struct that hasn't been defined because the compiler doesn't know their type.
However, you can use a pointer to a struct that hasn't been defined. This allows one to do something as follows:
foo.h:
typedef struct Foo Foo
Foo* Foo_new(int a, int b);
void Foo_destroy(Foo* this);
void Foo_set_a(Foo* this, int a);
void Foo_set_b(Foo* this, int b);
int Foo_get_a(Foo* this);
int Foo_get_b(Foo* this);
// ...
foo.c:
#include "a.h"
struct Foo {
int a;
int b;
};
Foo* Foo_new(int a, int b) {
Foo* this = malloc(sizeof(Foo));
this->a = a;
this->b = b;
return this;
}
void Foo_destroy(Foo* this) { free(this); }
void Foo_set_a(Foo* this, int a) { this->a = a; }
void Foo_set_b(Foo* this, int b) { this->b = b; }
int Foo_get_a(Foo* this) { return this->a; }
int Foo_get_b(Foo* this) { return this->b; }
// ...
main.c
#include <stdio.h>
#include "foo.h"
int main(void) {
Foo* foo = Foo_new(3, 4);
Foo_set_a(foo, 5);
printf("%d %d\n",
Foo_get_a(foo),
Foo_get_b(foo),
);
Foo_destroy(foo);
return 0;
}
You could even include the pointer in the typedef if you wanted a truly opaque type. Normally, that would be a bad practice, but it makes a certain amount in sense in this particular situation. See this for more on this concept.
Related
I am trying to create a struct that I will use in a function via pointers. The issue is that I do not want to use global variables therefore I can't use a pointer to a struct as a parameter for the function prototype if I try to define the struct in main file, since it has not been defined yet.
How would I go about doing this? What I think the solution is, is to define the struct in a header file, then create local variables of that type in the main file. Is this the right way to go about this? Would appreciate some info about what i'm actually doing here if this is correct.
Sorry if I did anything wrong when posting, Its my first time.
Example of what I am thinking the solution is
Main.h
#include <stdio.h>
typedef struct Vehicle{
int a;
char b;
};
function(Vehicle *p);
Main.c
#include "Main.h"
Vehicle Car1;
Vehicle *p=&Car1;
function(p);
The proper syntax for a typedef is
typedef T-IDENTIFIER IDENTIFIER-LIST;
wherein the comma separated identifiers listed in IDENTIFIER-LIST become aliases for T-IDENTIFIER. A lot of the time IDENTIFIER-LIST will consist of a single identifier.
For example, in
typedef int integer, number;
integer and number are now type aliases for int.
When it comes to using typedef with structs, the form
typedef struct foo { /* ... */ } foo_type;
is more or less shorthand for
typedef struct foo foo_type;
struct foo { /* ... */ };
but does allow you to typedef an anonymous struct
typedef struct { /* ... */ } foo_type;
With all that said, in your code you have omitted the IDENTIFIER-LIST from your typedef.
If main.c really does consist entirely of the code you've posted, it will not compile. Every C program needs an entry point, and in a hosted environment that is the function main with the signature int main(void) or int main(int argc, char **argv).
While you can declare variables outside of functions (i.e., globals), you can not call functions from outside of functions. Everything starts from main.
A working example program:
main.h:
typedef struct {
int a;
char b;
} Vehicle;
void function(Vehicle *p);
main.c:
#include <stdio.h>
#include "main.h"
int main(void) {
Vehicle car = { 51, 'A' };
function(&car);
}
void function(Vehicle *v) {
printf("Vehicle: a: %d, b: %c\n", v->a, v->b);
}
I can't use the struct as a parameter for the function prototype
You misunderstood something.
Your typedef is rather useless.
You of course can use pointers to structs as function parameters and in the function prototypes.
typedef struct {
int a;
char b;
} Vehicle;
int foo(Vehicle *); // prototype
You can't call function not outside other functions (as it is shown in the main.c
Im having an issue in my program where I define a structure type but not a structure variable in a header as such.
typedef struct
{
int a;
int b;
int c;
Token d;
} Foo;
I then want to use this struct foo later on in a .c file that does infix to postfix
#include "header"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
int infix2postfix(char *infix, Arr arr)
{
struct Foo foo;
char szToken[MAX_TOKEN];
Stack stack = newStack();
infix = getToken(infix, szToken, MAX_TOKEN); //provides next token to be scanned by function.
... //push pop using switch case didn't post code for simplicity.
case...
push(stack, *foo.a);
...
case...
pop(stack);
...
goOut(arr, *foo.d); //goOut(function that populates and "arr" Array from printing.
}
So when I compile here I get
error: storage size of ‘foo’ isn’t known struct Foo foo;
I have tried struct Foo *foo = malloc(sizeof foo); to allocate memory but it messes up my push(stack, *foo.a); and goOut(arr, *foo.d); How do I go about fixing this? Do I have to allocate memory in the infix2postfix function first then declare a structure variable?
You defined a type Foo which is a tagless struct type. You could have a separate struct Foo { int anonymous; char name[MAX_NAME]; }; which is wholly unrelated to the type Foo. (It would be very confusing for humans, but the compiler would have no problem.)
In your function, you should write:
int infix2postfix(char *infix, Arr arr)
{
Foo foo;
you have already defined Foo as a typedef struct, so you do not use struct Foo again to declare foo, just use
Foo foo; to declare not struct Foo foo;
Is there a way to design a macro that could ensure an element is at the start of a struct during it's definition? For example:
typedef struct {
START(int a);
} b;
// Becomes
typedef struct {
int a;
} b;
But generate a compiletime error when it isn't the first element?
typedef struct {
int c;
START(int a);
} b;
// Generate an error
I was thinking you could use a combo of the OFFSETOF and BUILD_BUG_ON_ZERO macros but this would require knowing the struct layout while initializing it, and produces an error because the variable is undeclared.
Is this possible in C?
Use a compile time assertion at the locations you actually assume that layout, instead of at the definition site. Of course you will need to actually define it at the start in order to pass the assertion.
Perhaps something like this would work for you:
#define typedef_header(x) typedef struct { x
typedef_header(int a);
int c;
} b;
int main()
{
b x;
}
The following code compiles and runs fine:
#include <stdio.h>
typedef int Someint;
typedef int Someint;
int main()
{
Someint b = 4;
printf("%d", b);
return 0;
}
The following code doesn't compile. It's giving me an error conflicting types for 'Somestruct'.
#include <stdio.h>
typedef struct
{
int x;
}
Somestruct;
typedef struct
{
int x;
}
Somestruct;
int main()
{
Somestruct b;
b.x = 4;
printf("%d", b.x);
return 0;
}
Why can I typedef one type (int in first code) twice without error ,but the same thing fails for another type (the structure above)? What is the difference between the two cases?
I'm using the MinGW compiler that came with CodeBlocks 12.11.
The thing is that when you do:
typedef struct
{
} Somestruct;
It creates an anonymous struct - you can expect some hidden implementation-defined guaranteed-unique placeholder identifier to be used - for which you specify the typedef. So, when you do it twice you get a conflict in having the same typedef-ed name asked to refer to two distinct structures. With int, you're simply repeating the original. If you give the struct an actual name then that lets you repeat the typedef:
typedef struct Somestruct
{
} Somestruct;
Because you're defining your typedef using an anonymous struct, both definitions are distinct.
The following doesn't do this, and works. (note that you can still only define the struct once)
#include <stdio.h>
typedef struct foo
{
int x;
}
Somestruct;
typedef struct foo Somestruct;
Lets say I have a header file foo.h which declares a struct variable
#include <stdio.h>
typedef struct foo_struct foo_s;
foo_s foo_function(int a);
foo_s bar_function(int b);
and a source file foo.c which actually defines the structure
#include "foo.h"
struct foo_struct
{
int a;
int b;
};
foo_s foo_function(int a)
{
foo_s fs;
fs.a = a;
return fs;
}
Now I want to access the structure defined in foo.c in another source file bar.c so I try the following:
#include "foo.h"
foo_s bar_function(int b)
{
foo_s fb;
fb.b = b;
return fb;
}
...and fail with bar.c:3:7: error: return type is an incomplete type
I sort of understand what the problem is but is there a workaround?
You're breaking your abstraction by needing to know the definition of struct foo_struct outside of foo.c. The whole point of making a struct definition "private" to a particular source file is so that other source files aren't aware of and cannot manipulate the members of struct foo_struct directly.
You either need to move bar into foo.c, or you need to put the struct definition in foo.h (making it public), or you need to define an interface that allows other translation units to allocate, set, read, and deallocate items of type foo_s without exposing the details of its type, similar to how the routines in stdio.h manipulate objects of type FILE, something like
foo_s *create_foo(int a, int b);
void set_foo(foo_s *f, char *property, int value);
int get_foo(foo_s *f, char *property);
void destroy_foo(foo_s **f); // sets f to NULL after deallocation.
You would add the above interface to foo.h and implement it in foo.c; functions in other translation units (source files) would use it like:
void blah(void)
{
foo_s *f = create_foo(0,0);
if (f)
{
set_foo(f, "a", 1);
set_foo(f, "b", 2);
printf("a = %d, b = %d\n", get_foo(f, "a"), get_foo(f, "b");
destroy_foo(&f);
assert(f == NULL);
}
}
There are probably a hundred better ways to do that, but you should get the idea.
No, there is no easy workaround.
In this code
typedef struct foo_struct foo_s;
foo_s fb;
fb.b = b;
the compiler only knows that foo_s is a struct, but it doesn't know if b is a member of that struct, or how large the struct is. And it definitely cannot know that it is the second member you want to assign a value to, so it just doesn't work.
The compiler can only tell what the code is supposed to do if you include the definition of the struct.