Reputation: 27455
I'm working on my own C-project and need some design/common_C_idiom advice. The problem I'm trying to solve is to open an input date stream of a configured device. But I want to keep configuration and device separated. Here is what I tried:
config.h
#ifndef CONFIG_H
#define CONFIG_H
typedef struct config_t config_t;
config_t* config_t_allocate(void);
void config_t_free(config_t *);
//functions to set configuration parameters
#endif //CONFIG_H
config.c
#include <stdlib.h>
#include "device.h"
struct config_t{
const char * name;
};
config_t* config_t_allocate(void){
return malloc(sizeof(config_t));
}
void config_t_free(config_t * config_ptr){
free(config_ptr);
}
device.h
#ifndef DEVICE_H
#define DEVICE_H
typedef struct config_t config_t;
typedef struct device_t device_t;
void configure_device(device_t**, config_t*);
//other device-related methods
#endif //DEVICE_H
device.c
#include "device.h"
#include <sys/fcntl.h>
struct device_t{
int fd;
};
//Does not compile. What is the confit_t type?
void configure_device(device_t** device, config_t* config_ptr){
*device = malloc(sizeof(**device));
(*device) -> fd = open(config_ptr -> name, O_RDONLY);
}
So I would like to share the config_t
type completed in config.c
across multiple translation units. The only thing I can imagine is to create a "private" header file containg the struct. Something like this:
types/configdef.h
#ifndef TYPES_CONFIG_DEF_H
#define TYPES_CONFIG_DEF_H
struct config_t{
const char * name;
};
#endif //TYPES_CONFIG_DEF_H
And include it everywhere I need the config_t
.
Upvotes: 0
Views: 80
Reputation: 755064
If you use an opaque type like config_t
, you forgo the option of accessing its members directly in the source code that isn't privy to the implementation details. You could provide a function to do that, though:
extern const char *config_t_get_name(config_t *config);
or thereabouts, declared in config.h
, defined in config.c
, used in device.c
.
But how about putting
struct config_t{ const char * name; };
into some header file which I will not expose (sort of library private) and using it everywhere in implementation C files. Isn't it common or does it have some drawbacks?
The primary alternative to access functions is, indeed, a 'private' header, but that's usually not as good as access functions. It can be done; it is not entirely uncommon, especially if the suite of functions that need access to the internals of the structure is too large to fit sanely in a single source file (or because local rules are 'one non-static function per source file', or …). The difficulty, then, is ensuring that files that should not be privy to the private header cannot (do not) use it. That suggests that the private header should not be installed with the library, and possibly the private header should be in a separate directory from the public header(s) for the project.
Consider whether you should enforce:
#include "project/headerX.h" // General, public headers for the project
#include "project/private/internal.h" // Private headers for limited use
You can then police the use of the private headers by using grep
or equivalent to find references that should not be allowed, etc. Alternatively, or perhaps in conjunction, use a distinctive naming scheme for private headers, using the pvt_
prefix to denote 'private':
#include "project/internal/pvt_config.h"
There are endless variations on the theme. Programmers will devise all sorts of schemes to gain access to private headers to make use of them. Ultimately, you have to trust your programmers to obey the rules — thou shalt not use private headers except in files explicitly granted permission to use them. If they cannot accept that discipline, maybe they shouldn't be on the project after all. Or maybe you should take time to understand why the recalcitrant programmers cannot use the access functions you provide — is there something wrong with the design?
You might search on Google (or your search engine of choice) for 'getters setters
'; the results seem to be informative. Add your language of choice (C++, Java, JavaScript figure prominently; C not so prominently but it does pull up references that would probably be helpful).
Upvotes: 5