4

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?

fsheikh
  • 406
  • 3
  • 11

2 Answers2

3

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.

John Bode
  • 106,204
  • 16
  • 103
  • 178
1

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.

Bo Persson
  • 86,087
  • 31
  • 138
  • 198