Static library structs and includes - c

I'm building up a static embedded C-library, which has an API header file, that lists all available functions. I am not sure about a few thing, that I would like to clarify first before I start implementing it.
First of all, since this is a C-Library for embedded systems, which has hardware FPU, I'm not sure what I should include to calculate the math functions like sinf() etc. Normally I use the hardware specific includes, but that is not avialable in this static C-library, since it can run on some STM32 or even some AVR etc. How can I solve this problem?
Further Lets say I have the files foo.c and foo.h, which provide some hidden functions in the library and then there is the api.h, which can be seen by a user and api.c, which is also hidden. In foo.h are now some structs defined, that I would like to return in a callback to a user. Since this structs are hidden, I'm not sure how I should handle this callbacks. Should I implement a handler in api.c, which maps the structs from the callback from foo.c and pass them to the users callback, where the structs are redefined (with different name) in api.h or are there solutions with less overhead?
When I would define the necessary structs for foo.h in api.h, I would need to include api.h in foo.h, but also foo.h in api.h, that is not a good idea I think.

For the first part of the question, the mathematical operations like sinf should be handled by the C standard library (you should check you specific version for support on your architecture). You can then use the math.h header and its functions, the compiler should then use the FPU to make the floating point computations.
For the second part, the usual way to show the user a hidden structure is with a foward declaration but the user will have to interact with the structure through pointers and access functions.
With you example, say we have four files:
api.h: public header
api.c: source code for functions from the public header
foo.h: library internal header (will not be shipped to the end-user)
foo.c: source code for the internal functions
The api.h is the only interesting file of those (have no changes).
// file: api.h
#ifndef API_H
#define API_H
struct foo; // forward declaration of the foo structure
typedef void (*callback_t)(struct foo*); // typedef for a callback taking a
// struct foo argument
void set_callback(callback_t fn);
#endif
Now we have a type for the callback and the type of the structure given to the callback, but the user cannot interact with the structure itself, since the compiler only knows it exists but does not know its content (nor storage size).
When the user writes a callback like in the below code, the user will need to have some access functions.
#include "api.h"
void user_callback(struct foo* arg) {
// user code here
}
The access functions are usually defined like this:
// in the file api.h or another header that the user has access to
int foo_get_value1(struct foo* arg);
void foo_set_value1(struct foo* arg, int new_value);
and those functions would be implemented in foo.c
struct foo {
int value1;
int value2;
};
int foo_get_value1(struct foo* arg) {
return arg->value1;
}
void foo_set_value1(struct foo* arg, int new_value) {
arg->value1 = new_value;
}
This approach has the added advantage that your foo_set functions can do validity checks to make sure you have appropriate values in your structure.
Please note: I did not add any checks to my access functions to avoid cluttering the code, but when passing a pointer to a function, you should always check it for NULL

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.

Exporting types from private headers via the public header

From what I understand, protection of implementation is a good principle to follow, so when writing a new library I decided to give it a shot. My goal is to protect internally used data types and only export the ones that are absolutely needed for people implementing my library.
Let say I have four files:
library_component.c:
#include "library_component.h"
struct my_data {
int stuff;
};
library_component.h:
// Private header
struct my_data;
library.c
#include "library_component.h"
#include "library.h"
library.h:
// Public header
// Include guards, etc...
typedef struct my_data my_data_type;
In this example library_component.c and library.c would get compiled into a shared library file library.so and installed along with library.h inside the host machine.
What's unclear to me, is how am I supposed to handle the struct my_data situation. I want to export it is as my_data_type. Is it possible to hide the typedef statement from the public header?
If library is the only module exposed to the caller - it is the actual API - then this design is fine. A nosy caller, who for some reason goes to dig up internal header files only used by library, can't do much with it anyway - struct my_data in the header is an incomplete type.
However, a less confusing alternative might be to write library_component.h as:
typedef struct my_data_t my_data_t;
And then use that very same definition in library.h - the type is declared in library_component.h and library.h gets access through it with #include. Then everything will be clear. In library_component.c you would have struct my_data_t { ....
And finally, all functions in library.h should be designed to use my_data_t*, which is a must since the type is incomplete and the caller won't be able to create instances of it.
This design method is known as opaque type/opaque pointers.
You can't hide the typedef from the users of the library because that is the type you want your users to use. This is not a problem in terms of protecting private types however.
The typedef acts as a forward declaration of struct my_data. So users of the library can create pointers to that type but not instances of that type. That protects the implementation details of struct my_data.
For example, your library can include functions like this:
struct my_data *get_new();
void do_something(struct my_data *data);
void do_something_else(struct my_data *data);
void cleanup(struct my_data *data);
These allow users to create instances of the struct via get_new, receiving a pointer to the instance, and to pass that pointer to other library functions to operate on it.

Implementing data hiding access specifiers in C language

Is there is a way to implement access specifiers like "private", "protected" in C language. I came across solutions in the internet about using "static" and "ifdefs" for making a function available only inside certain other functions.
Apart from these, is there any C implementation equivalent of using private and protected access specifiers in C++ classes?
C does not have access specifiers. The only way to hide something from your callers is to not provide its declaration in the header.
You can make it static in the translation unit:
myapi.h
extern int visibleVariable;
void visibleFunction();
myapi.c
int visibleVariable;
static int invisibleVariable;
void visibleFunction() {
...
}
static void invisibleFunction() {
...
}
You can also hide the definition of a struct by placing it in the implementation file. This way all fields of your struct would be private to the translation unit. The drawback to this approach is that the users of your API would be unable to declare variables of your struct's type, so they would need to deal with your struct through pointers.
C has no concept of inheritance, hence there is no equivalent of protected access.
C does not have user definable name spaces or access specifiers. Since you exclude (ab)use of preprocessor, the only way to get compiler error trying to access private parts of "classes" is to not have a .h file which exposes "private" stuff. They can still be put into "private" separate .h files (included by module's or library's own .c files, but not meant to be included from application code), or hidden behind #ifdefs (requiring special define to activate the "private" parts).
One common way to hide things is to use opaque structs AKA opaque pointers. For that approach, the code outside a module or library only has pointer to a struct, but no struct definition. And then it uses functions offered by the module to get an instance, access it, and finally release it.
With this approach, you easily get public interface: the functions you provide in the public .h file, as well as any public support structs which have definition there. The private interface is the code where the full struct definition is visible, and any functions which are not in the public .h file.
Protected access implies inheritance, which usually works very differently from C++, when implemented with C by hand, and which is too broad a subject to cover in this answer. The closest thing to this would probably be to have several .h files, which provide several levels of "public" access, and then it is responsibility of the programmer to not get into problems with them.
The good thing about this approach is, other code using the module does not need to be modified (or even recompiled), if struct is changed. Often struct might even be an union, and then the module's functions would branch based on the actual type, all invisibe from the code using it. Another good thing is, the module can control creation of structs, so it could for example have a pool of structs and avoid using heap, all invisible to the application code. One downside is, you can't have inline functions (because the inline function body in .h file would need the struct definition, which we are trying to hide here), which prevents some nice compiler optimizations in cases where performance is a concern.
Example (untested code written for this answer):
module.h:
// ...other standard header file stuff ...
// forward declaration of struct
struct module_data;
// "constructor" function
struct module_data *module_initialize_data(int value);
// modification function
int module_update_data(struct module_data *data, int adjust);
// "destructor" function
void module_release(struct module_data *data);
module.c
#include "module.h"
// struct definition only in the .c file
struct module_data {
int value;
};
struct module_data *module_initialize_data(int value) {
struct module_data *data = malloc(sizeof(*data));
data->value = value;
return data;
}
int module_update_data(struct module_data *data, int adjust) {
data->value += adjust;
return data->value;
}
void module_release(struct module_data *data) {
free(data);
}
Relevant Wikipedia links for reference:
https://en.wikipedia.org/wiki/Opaque_pointer
https://en.wikipedia.org/wiki/Opaque_data_type

Design issue in 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.

How to export/import a C struct from a DLL/ to a console application using __declspec( dllexport/import )

This is my first time dealing with DLLs. Following the MSDN documentation I created a header file fooExports.h with macros defined according to a preprocessor definition:
#ifdef FOODLL_EXPORTS
#define FOO_API __declspec( dllexport )
#else
#define FOO_API __declspec( dllimport )
My intention was to use this header both in my DLL implementation as well as in the console application. So far importing and exporting functions works just fine. The problem arrises when I try to export an already defined struct that I need as parameter for one of the exported functions. For example, in the aforementioned header file I declare FOO_API void foo( FooParams *args ) and args is a struct defined as follows:
typedef struct FooParams
{
char *a;
char *b;
void *whatever; //some other type
} FooParams;
This struct has to be defined in foo.h rather than in fooExports.h. Is there any way to export this struct without taking it out of it's original header file (taking into consideration that I want to keep the exports/imports centralized in fooExports.h).
What would be a better approach to doing this? The DLL is all C as well as the client application using it.
If the only use the client will ever have for FooParams is to get pointers to it returned from DLL functions and to pass those pointers to other DLL functions, you can make it an "opaque type": Put
typedef struct FooParams FooParams;
in fooExports.h. The FOO_API macro does not belong on that declaration. An opaque type means the client code cannot:
Create any variables of type FooParams (but FooParams * ptr = NULL; is okay).
Do anything at all with any member of FooParams.
Find sizeof(FooParams) - and therefore cannot correctly malloc space for one or more FooParams objects.
You can't #define macros visible to the client which do any of the above, either. So your DLL would need to have one or more "constructor" or "factory" functions, maybe something like
FOO_API FooParams* CreateFooParams(const char * input);
It's also good practice to define a matching "destructor" function like
FOO_API void DestroyFooParams(FooParams * p);
even if the definition is as simple as { free(p); }, because there can sometimes be issues if memory allocated inside a DLL is freed by code outside it or vice versa (because not all Windows code uses identical definitions of malloc and free).
If all this is too extreme, the only other option is to put or #include the struct definition in the exported header file and make it visible to clients. Without that, any attempt to do something to a FooParams, other than passing pointers around, is going to be impossible because the compiler won't know what's in a FooParams. The compiler (as opposed to the linker) takes information only from commandline arguments and #include-d files, not from libraries or DLLs.

Resources