There are a few ways of tackling this particular issue, depending on what you're trying to do.
First, your code seems to be conflating the structure name struct s_strukt
with the typedef name strukt
. In general, the typedef
would live in abstract.h
, where it would be available to both client code and to the implementation in abstract.c
(and I think that, in general, having a type name that is one letter different from -- and pronounced the same -- as an existing C keyword is going to lead to confusion and dismay).
If your goal is clear separation between interface and implementation, you can use what are called "opaque structures". This is what you get when you have a type that references a structure the definition of which isn't visible to the calling code (for example, the FILE
type used by fopen/fclose/read/write
, etc).
In abstract.h
, you would have:
#ifndef H_ABSTRACT
#define H_ABSTRACT
typedef struct s_strukt strukt;
strukt *create_strukt(void);
#endif
And in abstract.c
, you would have:
#include <stdio.h>
#include <stdlib.h>
#include "abstract.h"
struct s_strukt {
int x;
};
strukt *create_strukt() {
strukt *s = malloc(sizeof(strukt));
return s;
}
Given the above, you could write use_abstract.c
like this and it would compile without error:
#include <stdio.h>
#include "abstract.h"
int main() {
strukt *s = create_strukt();
return 0;
}
But there's a problem! Because strukt
is an opaque type, if you try to do this in use_abstract.c
:
s->x = 0;
It will fail:
use_abstract.c: In function ‘main’:
use_abstract.c:8:6: error: invalid use of incomplete typedef ‘strukt’ {aka ‘struct s_strukt’}
8 | s->x = 0;
| ^~
A typical solution for this is to implement routines in abstract.c
to get/set values in the opaque structure. E.g., make abstract.h
look like this:
#ifndef H_ABSTRACT
#define H_ABSTRACT
typedef struct s_strukt strukt;
strukt *create_strukt(void);
void strukt_set_x(strukt *s, int value);
int strukt_get_x(strukt *s);
#endif
And abstract.c
look like this:
#include <stdio.h>
#include <stdlib.h>
#include "abstract.h"
struct s_strukt {
int x;
};
strukt *create_strukt() {
strukt *s = malloc(sizeof(strukt));
return s;
}
void strukt_set_x(strukt *s, int x) {
s->x = x;
}
int strukt_get_x(strukt *s) {
return s->x;
}
And then write use_abstract.c
like this:
#include <stdio.h>
#include "abstract.h"
int main() {
int val;
strukt *s = create_strukt();
strukt_set_x(s, 0);
val = strukt_get_x(s);
printf("val is: %d
", val);
return 0;
}
But what if you don't want to use an opaque structure? Then you would write abstract.h
like this:
#ifndef H_ABSTRACT
#define H_ABSTRACT
typedef struct s_strukt {
int x;
} strukt;
strukt *create_strukt(void);
#endif
Because the structure definition is now in abstract.h
, where it's exposed both to the implementation in abstract.c
and the client code in use_abstract.c
, we no longer need getter/setter functions, because code in use_abstract.c
can access structure members directly. With the above, abstract.c
would look like:
#include <stdio.h>
#include <stdlib.h>
#include "abstract.h"
strukt *create_strukt() {
strukt *s = malloc(sizeof(strukt));
return s;
}
And use_abstract.c
would look like:
#include <stdio.h>
#include "abstract.h"
int main() {
strukt *s = create_strukt();
s->x = 0;
printf("x is: %d
", s->x);
return 0;
}