Design issue in C - c

I'm struggling with a design issue, and I'm trying to find the "Best Practice" answer for my situation.
Say I have a file called Logger.c (And Logger.h) that is responsible for logging actions in my program.
I want logger to be referenced by all my modules, so each module's has a
#include Logger.h.
Say I have a module called NTFS.c that is responsible for interaction with the NTFS FS, This module has special structs that are defined in its header, for example: NTFS_Partition.
Here is the problem:
On one hand, I want logger to be able to print to a log file a formatted representation of NTFS_Partition, and by that I must #include NTFS.h in Logger.h.
(Inside Logger.h)
#include NTFS_Partition
VOID Log_Partition(NTFS_Partition *part);
On the other hand, I am not sure Logger should re-reference modules that reference him.
Currently I'm seeing a two main choices:
1.Logger.h includes NTFS.h, and NTFS.c include Logger.h (This works)
2.I create a new header file called NTFS_Types.h that would be shared accross all the
modules, and would only contain the deceleration of NTFS structs (like NTFS_Partition).
Thanks a lot,
Michael.

You can create a shared header where all your structs are defined.
// structs.h
struct NTFS_Partition { .. };
struct FAT32_Partition { .. };
struct FAT16_Partition { .. };
Include it in logger.h.
// logger.h
#include "structs.h"
VOID Log_Partition(NTFS_Partition *part);
VOID Log_Partition(FAT32_Partition *part);
VOID Log_Partition(FAT16_Partition *part);
And include the logger.h in various source files.
// NTFS.c
#include "logger.h"
// FAT32.c
#include "logger.h"
// FAT16.c
#include "logger.h"
In C++, it's better to keep different irrelevant class definitions in different header files. But in C, placing different struct definitions in separate headers is probably an overkill.

It isn't entirely clear whether you are coding in C or C++; I'm going to assume C (so no overloaded function names, etc). It seems to me that you need to 'forward declare' your structures. In Logger.h, you write:
#ifndef LOGGER_H_INCLUDED
#define LOGGER_H_INCLUDED
struct NTFS_Partition; // No details - just the name (3 times)
struct FAT16_Partition;
struct FAT32_Partition;
...
void Log_NTFS_Partition(struct NTFS_Partition *part);
void Log_FAT16_Partition(struct FAT16_Partition *part);
void Log_FAT32_Partition(struct FAT32_Partition *part);
#endif // LOGGER_H_INCLUDED
This is all the information that a general client (of Logger.h) needs to know.
If a specific client is dealing with NTFS partitions, then it will not only include Logger.h but also NTFS.h, which will provide the full definition of struct NTFS_Partition { ... };, so the client can create instances of the structure and populate it with data. The code that implements the logging, Logger.c, will also include Logger.h and NTFS.h (and FAT16.h and FAT32.h), of course, so that it too can reference the members of the structures.
The header for a service (such as Logger.h) should provide the minimal amount of information that the clients of the service need for compilation. The implementation file may need more information, but can collect the extra information from headers that provide it.
One advantage of using the struct tag notation is precisely that it can be repeated as often as necessary without messing anything up. If you don't have C11, you can't repeat a typedef, so if you write:
typedef struct NTFS_Partition NTFS_Partition;
you must only include that line once. The difficulty is making sure that it is only defined once. For that, you probably use a header such as FSTypes.h to define the file-system typedefs that is properly protected by header guards and is included in any file that needs any of the typedefs. You can then reference the types without the preceding struct keyword.
If you code in C++, the typedef isn't necessary; struct NTFS_Partition; declares that there is such a structure type and also declares NTFS_Partition as a name for that type. If your code is bilingual, use the typedef version; it works in both C and C++.
Note that if your functions such as Log_NTFS_Partition() take an actual structure instead of a pointer to a structure, then you have to have the definition of the structure in scope. If the functions only take pointers, though, a forward declaration is sufficient.

Related

Is there a way to make a struct definition "private" to a single translation unit in C?

In C, you can use the static keyword to make global variables and functions private to the file in which they're defined. The compiler won't export these symbols, and thus the linker will not allow other modules to use these definitions.
However, I'm struggling to figure out how to restrict a struct definition such that it doesn't get added as an exported symbol that could accidentally be used by another module during the linking process. I would like to restrict this to the only file in which its defined.
Here are my attempts thus far which I've been struggling with.
// structure that is visible to other modules
struct PrivateStruct
{
int hello;
int there;
};
// this seems to throw an error
static struct PrivateStruct
{
int hello;
int there;
};
// i would ideally like to also wrap in the struct in a typedef, but this definitely doesn't work.
typedef static struct PrivateStruct
{
int hello;
int there;
} PrivateStruct;
Edit: I realize if I just define this struct in the .c file, others won't know about it. But won't it still technically be an exported symbol by the compiler? It would be nice to prevent this behavior.
I realize if I just define this struct in the .c file, others won't know about it. But won't it still technically be an exported symbol by the compiler?
No. Whether you are talking about structure tags or typedefed identifiers, these have no linkage. Always. There is no sense in which it would be reasonable to say that they are exported symbols.
This is among the reasons that header files are used in C. If you want to use a structure type in one compilation unit that is compatible with a structure type in a different compilation unit then compatible structure type declarations must appear in both. Putting the definition in a header makes it pretty easy to achieve that.
yes..... you can use pointers to the structure, and to the outer world it is not deferrable. Normally, that requires two header files, the first is the public one:
header mystruct.h
This header is public, used by client code.
struct my_opaque;
/* we cannot use *p fields below, as the struct my_opaque is
* incompletely defined here. */
void function_using(struct my_opaque *p, ...);
header mystructP.h
This header is private, and includes the public header file to maintain the
API to the client code.
#include "mystruct.h" /* safety include (1) */
struct my_opaque {
/* ... */
};
implementation mystruct.c
In implementation code, we include the private header file, and so, we have full access to the structure fields.
#include "mystructP.h"
/* we have full definition, as we included mystructP.h */
void function_using(struct my_opaque *p,
...)
{
... /* we can use p->fields here */
}
(1) the safety #include allows to change the struct my_opaque and the API functions, and the compiler to blame you if you change something in the api to the caller modules, forcing you to recompile if you change something in that API.

How to share opaque type across multiple translation units?

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

How to use struct as argument of a function when the struct is declared in another file?

I'm writing a c project and I'm trying to keep all the struct declarations in the relevant .h files. This allows me to use them in any of the .c files by including the relevant header.
I'm also avoiding the inclusion of header files of my project in other header files. I guess this will make the code easier to read and maintain.
My question is how to avoid the inclusion of a header which contains the declaration of a struct in the header file that uses that struct. Is there any way of doing that?. (I didn't find an answer for this, sorry if it's duplicated).
Here is a snippet:
cmd.c
#include "cmd.h"
#include "params.h" //This allows usage of struct testPars
void move_parameters(struct testPars *testP) {
...
}
cmd.h
#ifndef CMD_H
#define CMD_H
#include "params.h" //I want to avoid this include in this file
void move_parameters(struct testPars *testP) ;
#endif
params.h
#ifndef PARAMS_H
#define PARAMS_H
struct testPars {
char name[16];
double value;
};
#endif
Overall, there's a lot of confusion about proper program design here.
I'm trying to keep all the struct declarations in the relevant .h files. This allows me to use them in any of the .c files by including the relevant header.
This is acceptable practice for quick & dirty programming where you have no private encapsulation, or if the structs are of a simple nature.
But for professional programs where the structs represent more complex ADTs etc, you should only keep a forward declaration in the header files, and define the struct inside the corresponding c file. This leads to private encapsulation and modularisation, i.e. good program design. (Search for examples of "opaque type" or "opaque pointers". The formal term for such forward declarations is incomplete type.)
What you are trying to do sounds like the above but completely backwards: expose the definition to the caller, but don't use it yourself. And obviously you can't use a struct that you haven't included and made visible to your program, because that doesn't make any sense.
I'm also avoiding the inclusion of header files of my project in other header files. I guess this will make the code easier to read and maintain.
This is a bad idea. Each of your header files is to be regarded as the public documentation of what the corresponding c file does and how it should be used. While the c file can be regarded as private data, the content is nothing that the caller should concern themselves with.
An important part of that header file documentation is to list all dependencies that this module has, so that other programmers can quickly take a glance at the top of your header file and immediately tell which files that are needed in order to compile this particular module.
Good program design strives for as few dependencies as possible: "loose coupling". Therefore all #includes are regarded as important information that should be put on top of the header file. Header files that aren't used should not be included.
The c file should not contain any includes except its own header file.

forward declaration of typedefed structs

In C often structs are typedefed to avoid writing struct everywhere.
When using this names as opaque pointer parameters in headers you have to forward declare them. It is rather annoying that the whole typedef has to be duplicated.
Example:
some header defines some types:
typedef struct sBlaBlaFooBar{
int someData;
}BlaBlaFooBar;
Some other header uses this structure as pointer parameter. But to avoid huge include dependencies BlaBlaFooBar.h should not be included and just a forward declaration is used.
So you have to write typedef struct sBlaBlaFooBar BlaBlaFooBar; to forward declare it.
That does bother me is the redundancy that i have to know the tag name of the structure because normally it does not matter. And if it is changed, all the forward declarations also have to be changed even if the typename is the same.
Is there some smart way around this?
more detailed explanation:
a lot of headers with structure definitions (that may be also composed structures (just to show deep dependency graphs))
s1.h
s2.h
s3.h
s4.h
a BlaBlaFooBar header with a BlaBlaFooBar structure that is a composite of all these.
Additional structures BlaBlaBarFoo with similar topology (from other sub structures)
then modules that defines new structures NewStruct and functions NewStruct_create(NewStruct* out, const BlaBlaFooBar* in); that processes
the above structures as input. These headers only need the typedefs and only the implementation has to know about exact BlaBlaFooBar structure definitions.
Addional modules that only work on NewStruct and to not necessarily have to be recompiled if BlaBlaFooBar changes.
So to avoid these kind of dependencies the structures have to be forward declared in the header and the c-file includes the definition.
Use 2 include files:
blabla.h
#include "light_dependencies.h"
typedef struct sBlaBlaFooBar BlaBlaFooBar;
blabla_internal.h
#include "blabla.h"
#include "heavy_dependencies.h"
struct sBlaBlaFooBar {
...
};
blabla.c
#include "blabla_internal.h"
/* Here is code which deals with the internals of the struct */
usercode.c
#include "blabla.h"
/* Here is code which only passes struct pointers around */

Howto handle typedefs without include headers in headers

As for working on a larger project, I want to throw in some own types (e.g. myType). The "rushing in"-approach would be, to put those typedefs into an header (lets say myType.h), together with a bunch of functions working on those types.
If I use the new type somewhere, I include myType.h to my source-file. Fine.
But if I want to use the new type somewhere as an argument in a function-signature, I need to include the myType.h to the header of the module containing the function. With one or another typedef, this seems to be okay for me, but the more types I have, the more includes in headers I need, possible including further header, while using type including other own types. This is resulting in what I call "dependency hell".
Is there a clever, stylish, best practice, what-so-ever way to solve this dilemma?
I'm aware of the possibility to pass those types as void-pointer, casting them back inside the function, but then I loose important type-checking from the compiler.
Furher, extern is considered worst-practice around here..
EDIT:
In detail:
myType.h:
#include "otherType.h"
typedef struct {
char Name[32];
int Size;
otherType someType;
} myType;
processSomeHow(myType _myType, int NewSize);
otherType.h
#define SOME_CONST 32
typedef struct { [...] } otherType;
someModule.h:
#include "myType.h"
int specialProcessSomeHow(myType _myType);
someModule.c:
int specialProcessSomeHow(myType _myType)
{
int Size = 64;
return(processSomeHow(_myType, Size));
}
Now I include otherType.h indirectly to someModule.h, even worse, I include it to every module, that includes someModule.h. Now I have a SOME_CONST everywhere and it's hard to figure out, from where it comes. I have to maintain two include trees.
like in the gtk library you can use one headfile and split it on your needs.
type.h
- myType.h
-- someType.h
- otherType.h
- List item
and on your CONST-Problem:
If you just need it for one c.file. Don't use them in HeaderFile.
And you could name them like "MY_TYPE_SOME_CONST" or "OTHER_TYPE_SOME_CONST";
//EDIT:
to make it clear: just add 'this.h' file and name it.
#ifndef TYPE_H_
#define TYPE_H_
#include myType.h
#include someType.h
#include otherType.h
#endif /* TYPE_H_ */
now you can use "#include this.h" for each file you need your types.
(this.h is not real, name it to something unique)
You can (and probably should) use forward declarations for your custom types. See details here: typedef stuct with forward declaration in C
Your interfaces (the headers) should have incomplete types (i.e. pointers to your custom types) and inside the source code (c files) you should include the My_Type.h.
You're worrying unnecessarily : There is no 'dependency hell', precisely because you are giving the compiler all the information it needs to do it's job.
Here's my rules for this:
Always, always use header guards.
Every .h file should
explicitly #include every other .h file it needs in order to compile,
and no more.
So if b.h uses a type from a.h, then b.h must #include "a.h". If b.c uses functions from a.h, but b.g doesn't use types from it, then b.c should #include a.h.
There's no need for extern keyword on functions in .h files, because IIRC modern compilers deduce this correctly.
Using extern for global variables may well be frowned on, with good
reason.
Cluttering of global namespace. C++ namespaces address this, but in C you have to use naming conventions for all global types, functions and #defines. Pick a convention that works for you : I've seen teams successfully use a LETTER-DIGIT-DIGIT prefix for every source file, so foo.h might become (for example) B04_foo.h, and all functions/types get the same B04_ prefix. It's a bit crude, but it works. As I say, pick one that works for you.

Resources