Reputation: 637
I'd like to organize my code in c, so it works a little bit like the public
and private
keywords in c++
specifically, I have some functions that will be used as a library in other projects, and I would like to make public
only the functions that are used by the projects, not the functions necessary for the internal actions
it would be easy if I could have all of them in the same file.c, but my school rules prevent me against that
I hope an example will be clear :
(A) struct definition (B) struct definition
in header.h in second_file.c
+----------------------+ +----------------------+
| header.h | | header.h |
------------------------ ------------------------
| #ifndef HEADER_H | | #ifndef HEADER_H |
| # define HEADER_H | | # define HEADER_H |
| | | |
| typedef struct foo | | |
| { | | |
| type param_1; | | |
| type param_2; | | |
| } t_foo; | | |
| | | |
| void action_a(void); | | void action_a(void); |
| void action_b(void); | | void action_b(void); |
| | | |
| #endif | | #endif |
+----------------------+ +----------------------+
+----------------------+ +----------------------+
| first_file.c | | first_file.c |
------------------------ ------------------------
| # include header.h | | #include header.h |
| | | |
| // prototypes | | // prototypes |
| void utils_a(void); | | void utils_a(void); |
| void utils_b(void); | | void utils_b(void); |
| | | |
| | | // struct prototype |
| | | t_foo; |
| | | |
| void action_a(void){ | | void action_a(void){ |
| // do something; | | // do something; |
| // use t_foo; | | // use t_foo; |
| } | | } |
| void action_b(void){ | | void action_b(void){ |
| // do something; | | // do something; |
| } | | } |
+----------------------+ +----------------------+
+----------------------+ +----------------------+
| second_file.c | | second_file.c |
------------------------ ------------------------
| # include header.h | | #include header.h |
| | | |
| | | typedef struct foo |
| | | { |
| | | type param_1; |
| | | type param_2; |
| | | } t_foo; |
| | | |
| void utils_a(void) { | | void utils_a(void) { |
| // do something; | | // do something; |
| // use t_foo; | | // use t_foo; |
| } | | } |
| void utils_b(void) { | | void utils_b(void) { |
| // do something; | | // do something; |
| } | | } |
+----------------------+ +----------------------+
case A
works, but not case B
as you can see, in both cases (A
and B
) the header doesn't include the utils functions, they cannot be used by other functions (unless they include the prototype themselves), the header doesn't include them
I would like to do the same for the struct (which is used in both files.c), because this struct is only a utility for the functions, but has no purpose to be called elsewhere
header.h
#ifndef HEADER_H
# define HEADER_H
#include <stdlib.h> // malloc()
#include <stdio.h> // printf()
// CASE A ONLY
// typedef struct foo {
// int param;
// } t_foo;
// CASE A END
// CASE B ONLY
typedef struct foo t_foo;
// CASE B END
t_foo **allocate_foo(void);
#endif
first_file.c
#include "header.h"
int main(void)
{
t_foo **tfoo;
tfoo = allocate_foo();
(*tfoo)->param = 1;
printf("%i\n", (*tfoo)->param);
return (0);
}
second_file.c
#include "header.h"
// CASE B ONLY
struct foo {
int param;
};
// CASE B END
t_foo **allocate_foo(void)
{
static t_foo *tfoo;
tfoo = malloc(sizeof(t_foo));
return (&tfoo);
}
case A compiles fine and prints 1
, but case B throw an error at compilation :
first_file.c: In function ‘main’:
first_file.c:8:9: error: dereferencing pointer to incomplete type ‘t_foo {aka struct foo}’
(*tfoo)->param = 1;
^~
Upvotes: 1
Views: 502
Reputation: 108968
The usual most basic solution is to make public the struct type identifier, but keep the definition private ... aka opaque pointer ... something like FILE
/* library.h */
#ifndef LIBRARY_H_INCLUDED
#define LIBRARY_H_INCLUDED
struct foo; // struct foo exists; it's definition is elsewhere
struct foo *newfoo(int);
void printfoo(struct foo *);
void killfoo(struct foo *);
#endif // LIBRARY_H_INCLUDED
/* library.c */
#include <stdio.h>
#include <stdlib.h>
#include "library.h"
struct foo { int bar; }; // struct foo has a single member
struct foo *newfoo(int n) {
struct foo *r = malloc(sizeof *r);
if (r) r->bar = n;
return r;
}
void printfoo(struct foo *s) {
printf("%d\n", s->bar);
}
void killfoo(struct foo *s) {
free(s);
}
/* main.c */
#include "library.h"
int main(void) {
struct foo *p = newfoo(42);
if (p) {
printfoo(p);
killfoo(p);
}
return 0;
}
Upvotes: 3