How to use struct declare

90 Views Asked by At

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?

3

There are 3 best solutions below

5
On

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

1
On

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)

0
On

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.