Global union for different modules - c

I have MCU code (for AVR) with set of different drivers. Driver in use is selected at startup time (in init code) and only one of the drivers will be used at a time. Therefore, i can alias all of RAM segments into the same location. That is required, as RAM is very limited and all of drivers require 2-3 KB of storage for buffers etc.
Currently i have structures typedef'ed in all header files:
driver1.h:
typedef struct {
// Driver-specific variables for internal use.
// None of those and accessed from outside C-file
int internal_variable1_for_driver1;
int internal_variable2_for_driver1;
...
} st_driver1_t;
Other drivers have similar structures
In all_drivers.h:
#include "driver1.h"
#include "driver2.h"
#include "driver3.h"
...
union {
st_driver1_t DRV1;
st_driver2_t DRV2;
st_driver3_t DRV3;
...
} DRV;
DISCLAIMER: I understand that all RAM access from modules, other than selected one, should be disabled as it will alter whole union. I have a lot of ASM code in portfolio and that's obvious for me.
Now i have some conflicts because i have to include all_drivers.h, and therefore all driverN.h files into each driver. I want to hide all those headers from all of other drivers.
Is it ok to define all driver-specific structures with __attribute__((common)) in C-files and therefore hide all of structure from headers. As i understand, linker will merge all those structures into overlapping segment and create some analog of union.
driver1.c:
struct __attribute__((common)) {
int var1;
int var2;
...
} DRV;
driver2.c:
struct __attribute__((common)) {
long OtherVar1;
int ExtraOne;
...
} DRV;
Also, should I define those structs as static or not? Will this solution be stable or is it undocumented hack?

Is it ok to define all driver-specific structures with __attribute__((common))
With GCC and compatible compilers, you can use __attribute__((__common__)) for common variables (and __attribute__((__no_common__)) if some variables should not be common, but common is the default).
GCC switched its default behaviour from -fcommon to -fno-common some time ago (in 2020 with v10), so you can also compile all compilation units that need this with -fcommon.
should I define those structs as static [...]?
No. There are some conditions that objects must meet to be coalesced as common:
The objects are global (thus also in static storage).
The objects don't have initializers.
The objects have the same (assembly) name.
The compiler must be advised to put the objects in common as discussed above.
Sometimes it's preferred that the objects don't have the same name on C/C++ level, for example that the object for driver1 is named driver1 etc. That's fine if the objects have the same name on assembly level, which can be achieved by using the same assembly name for all such objects. This is a feature provided by GCC. The following example sets the assembly name to asm_name, so in the assembly code the name asm_name will be used, but in C code you use driver1:
typedef struct { ... } driver1_t;
__attribute__((__common__))
driver1_t driver1 __asm ("asm_name");
If the ABI requires leading underscores, you should use a name that fits that ABI and use an assembly name that starts with an _ like _asm_name.
There are use cases where common is much clearer and more convenient than putting all objects into a union, so don't be discouraged by these comments.

Related

TI arm compiler not aligning struct members

I'm having this struct here (bool is an unsigned char)
typedef struct
{
bool a;
int b;
int c;
} test_t;
If I look at the memory of a variable using this type declared on stack I see that the aligned of member b is not correct and is not on 4 bytes boundary.
EDIT: This is caused by the inclusion of FreeRTOS_IP.h which includes a ported file for ti CCS pack_struct_start.h / pack_struct_end.h. The pack_struct_end.h file is not working correctly causing all remaining structs to stay packed.
Why the TI compiler packs my structure by default and then access the memory like they are not packed?
The compiler does what you tell it to do. In your case, you don't tell it very much, so the compiler does what others tell it to instead.
Specifically, your structure is probably in a header file that gets included in a random string of #includes in different files, but since you don't specify packing parameters (which by the way are #pragma pack, not the all-or-nothing gcc-specific attribute) it uses whatever leaked from the other header files you included.
Here's the lesson to learn from this: if you care at all, at any point, about the memory layout of your structure (ie, if you use it to lazily access memory from files or network data), always specify a packing attribute on your structure. No exceptions, ever. Also clean up after yourself (#pragma pack(pop)).

Is there a size limit to how many members or the type types of variables a structure may contain?

I ran into some weird issues (at compile time) with my embedded C code when I increased the size of the array from size [2] to [27] which contained structured metadata. So it is obvious that this is a nested structured style program and NOT my original work!
I remember in assembly code instructions, there used to be a JMP FAR, JMP NEAR/SHORT.. Is there any such limitations in structures (obviously there is no jump in structures). Could there be a condition that the compiler cannot assign a contiguous memory block for a structure because there is a limit to it and fails during compilation.
SOME CLUE: The fix as i recall was to move the member (array member)from original structure to another nested structure. That's the reason why i deduced that there maybe a limitation.
//STRUCTURES
typedef UINT8 P_Name_t[5];
typedef UINT8 ChipSN_t[3];
typedef struct
{
ChipSN_t ChipSN;
<other members>
} ChipIdent_t;
typedef struct Data_t
{
ChipIdent_t ReadOnlyMemID;
<other members>
} Data_t;
typedef struct
{
P_Name_t NameOfPart;
<other members>
} Log_t;
Data_t Data_Src;
typedef struct
{
P_Name_t NameOfPart;
ChipSN_t ChipSN;
}PartNum_ID_t;
typedef struct
{
PartNum_ID_t PN_ChipID[27];
<other members>;
}
According to standard, there is a limitation; but the limitation is much more than the size you mentioned here. C89 and C99 standard has the limit of 1023 structure members. See below text from the standard.
5.2.4.1 Translation limits
— 1023 members in a single structure or union
So looks like if your code is correct and limited to 1023 structure members the compiler you are using may have the limitation.
There may indeed be a limit to the number of structure elements your compiler can handle for a single structure, but as MCG quoted from the C Standard, this limit must be at least 1023 for compliant compilers and most compilers have higher limits or no practical limits at all.
I suspect the problem is elsewhere:
The Makefile for your project may have incomplete dependencies on the header file with the structure definitions: modules compiled with different definitions will be incompatible and produce undefined behavior. Remove all object files and recompile the project.
Some assembly modules may rely on the original structure layout: changing the definition will only affect the recompiled C modules.
Some library modules or OS system calls may rely on the original layout. Recompiling all libraries or even patching the OS may be required.
Some functions may rely on the original layout and use casts to access some of the structures via another type. Changing the layout may break such code, which is brittle anyway as even changing compilers may produce similar problems.
It is also possible that some of the type be multiply defined in different modules. This is poor and very error prone coding style as changing only one of the definitions will lead to undefined behavior when the object modules are linked together.

Program organization with device drivers in C

Say I have two device drivers and I want them to share the same interface so a caller doesn't know which driver it is talking to exactly. How would I organize this in C? I have thought of a couple of ways:
First: Create a pair of .c/.h files for both drivers with the same interface and create a switch in the caller:
//main.c:
#ifdef USING_DRIVER_1
#include "driver_1.h"
#else
#include "driver_2.h"
#endif // USING_DRIVER_1
Second: Use a single header and create a file-long switch in the drivers' source file like so:
//driver_1.c:
#ifdef USING_DRIVER_1
#include "driver.h"
bool func(uint32_t var)
{
foo(var);
}
#endif // USING_DRIVER_1
//driver_2.c:
#ifndef USING_DRIVER_1
#include "driver.h"
bool func(uint32_t var)
{
bar(var);
}
#endif // !USING_DRIVER_1
Third: This one is a lot like the second one but instead of using switch statements in files themselves, a specific driver is chosen in the makefile or IDE equivalent:
#makefile:
SRC = main.c
#SRC += driver_1.c
SRC += driver_2.c
I'm sure one of these is superior to others and there are probably some I haven't thought of. How is it done in practice?
EDIT:
Details about my particular system: my target is an ARM microcontroller and my dev. environment is an IDE. Device drivers are for two different revisions and will never be used at the same time so each build should contain only one version. Devices themselves are modems operating via AT commands.
All three variants are actually useful. Which to choose depends on what you actually need:
Selecting the driver from the caller would add both drivers to the code. That only makes sense if you switch drivers at run-time. Then it would be the (only) way to go. Use e.g. function pointers or two identical const structs which provide the interface (function pointer and possibly other data).
A global switch is plain ugly and not possible across functions and declarations. Better would be conditional compilation using #if .. #elif #end. That makes sense if the two drivers have only minor differences, e.g. different SPI interfaces (SPI1 vs. SPI2 ...). Then this is the way to go. With some effort in the build-tool you can even use this for case 1. (one file for two different drivers, but not my recommendation).
If both drivers are substantial different in their implementation, but have the same interface, take the third approach, but use a single header or both drivers (see below).
Note for all but the first approach, both drivers have to provide an identical interface to the application. The first approach actually allows for differences, but that would actually require the user code treat them different and that's likely not what you want.
Using a single header file for both drivers (e.g.: "spi_memory.h" and "spi_flash.c" vs. "spi_eeprom.c") does ensure the application does not see an actual difference - as long as the drivers also behave identically, of course. Minor differences can be caught by variables in the interface (e.g. extern size_t memory_size;) or functions (the better approach).
I recommend using pointers to functions. For example:
struct driver_api {
bool (*pFunc)(uint32_t);
} DriverApi;
void initializeApi(struct driver_api *pApi);
// driver1.c:
void initializeApi(struct driver_api *pApi)
{
pApi->pFunc = bar;
}
// driver2.c:
void initializeApi(struct driver_api *pApi)
{
pApi->pFunc = foo;
}
Another thing you might consider is removing the #ifndef USING_DRIVER_1 checks from your source files. Use a build system (e.g. make) and specify which source files should be included in the project. Then, based on some compile time option (such as a command line argument) include driver1.c or driver2.c, but never both.
The "advantage" of the pointers is that you can compile both APIs and then decide at runtime (even changing it mid run, for whatever reason).

How can I share an array between the C files of a library, without the array being visible to the outside? [duplicate]

I am writing a C (shared) library. It started out as a single translation unit, in which I could define a couple of static global variables, to be hidden from external modules.
Now that the library has grown, I want to break the module into a couple of smaller source files. The problem is that now I have two options for the mentioned globals:
Have private copies at each source file and somehow sync their values via function calls - this will get very ugly very fast.
Remove the static definition, so the variables are shared across all translation units using extern - but now application code that is linked against the library can access these globals, if the required declaration is made there.
So, is there a neat way for making private global variable shared across multiple, specific translation units?
You want the visibility attribute extension of GCC.
Practically, something like:
#define MODULE_VISIBILITY __attribute__ ((visibility ("hidden")))
#define PUBLIC_VISIBILITY __attribute__ ((visibility ("default")))
(You probably want to #ifdef the above macros, using some configuration tricks à la autoconfand other autotools; on other systems you would just have empty definitions like #define PUBLIC_VISIBILITY /*empty*/ etc...)
Then, declare a variable:
int module_var MODULE_VISIBILITY;
or a function
void module_function (int) MODULE_VISIBILITY;
Then you can use module_var or call module_function inside your shared library, but not outside.
See also the -fvisibility code generation option of GCC.
BTW, you could also compile your whole library with -Dsomeglobal=alongname3419a6 and use someglobal as usual; to really find it your user would need to pass the same preprocessor definition to the compiler, and you can make the name alongname3419a6 random and improbable enough to make the collision improbable.
PS. This visibility is specific to GCC (and probably to ELF shared libraries such as those on Linux). It won't work without GCC or outside of shared libraries.... so is quite Linux specific (even if some few other systems, perhaps Solaris with GCC, have it). Probably some other compilers (clang from LLVM) might support also that on Linux for shared libraries (not static ones). Actually, the real hiding (to the several compilation units of a single shared library) is done mostly by the linker (because the ELF shared libraries permit that).
The easiest ("old-school") solution is to simply not declare the variable in the intended public header.
Split your libraries header into "header.h" and "header-internal.h", and declare internal stuff in the latter one.
Of course, you should also take care to protect your library-global variable's name so that it doesn't collide with user code; presumably you already have a prefix that you use for the functions for this purpose.
You can also wrap the variable(s) in a struct, to make it cleaner since then only one actual symbol is globally visible.
You can obfuscate things with disguised structs, if you really want to hide the information as best as possible. e.g. in a header file,
struct data_s {
void *v;
};
And somewhere in your source:
struct data_s data;
struct gbs {
// declare all your globals here
} gbss;
and then:
data.v = &gbss;
You can then access all the globals via: ((struct gbs *)data.v)->
I know that this will not be what you literally intended, but you can leave the global variables static and divide them into multiple source files.
Copy the functions that write to the corresponding static variable in the same source file also declared static.
Declare functions that read the static variable so that external source files of the same module can read it's value.
In a way making it less global. If possible, best logic for breaking big files into smaller ones, is to make that decision based on the data.
If it is not possible to do it this way than you can bump all the global variables into one source file as static and access them from the other source files of the module by functions, making it official so if someone is manipulating your global variables at least you know how.
But then it probably is better to use #unwind's method.

Is there any way I can make "protected" typedef's in C?

if you want to cut to the chase, please skip down to the last two paragraphs. If you're interested in my predicament and the steps I've taken to solve it, continue reading directly below.
I am currently developing portions of a C library as part of my internship. So naturally, there are some parts of code which should not be accessible to the user while others should be. I am basically developing several architecture-optimized random number generators (RNG's)(uniform, Gaussian, and exponential distributed numbers). The latter two RNG's depend on the uniform generator , which is in a different kernel (project). So, in the case that the user wants to use more than one RNG, I want to make sure I'm not duplicating code needlessly since we are constrained with memory (no point in having the same function defined multiple times at different addresses in the code segment).
Now here's where the problem arises. The convention for all other kernels in the library is that we have a two header files and two C files (one each for the natural C implementation and the optimized C version (which may use some intrinsic functions and assembly and/or have some restrictions to make it faster and better for our architecture). This is followed by another C file (a testbench) where our main function is located and it tests both implementations and compares the results. With that said, we cannot really add an additional header file for private or protected items nor can we add a global header file for all these generators.
To combat this restriction, I used extern functions and extern const int's in the C files which depend on the uniform RNG rather than #define's at the top of each C file in order to make the code more portable and easily modified in one place. This worked for the most part.
However, the tricky bit is that we are using an internal type within these kernels (which should not be seen by the user and should not be placed in the header file). Again, for portability, I would like to be able to change the definition of this typedef in one place rather than in multiple places in multiple kernels since the library may be used for another platform later on and for the algorithms to work it is critical that I use 32-bit types.
So basically I'm wondering if there's any way I can make a typedef "protected" in C. That is, I need it to be visible among all C files which need it, but invisible to the user. It can be in one of the header files, but must not be visible to the user who will be including that header file in his/her project, whatever that may be.
============================Edit================================
I should also note that the typedef I am using is an unsigned int. so
typedef unsigned int myType
No structures involved.
============================Super Edit==========================
The use of stdint.h is also forbidden :(
I am expanding on Jens Gustedt’s answer since the OP still has questions.
First, it is unclear why you have separate header files for the two implementations (“natural C” and “optimized C”). If they implement the same API, one header should serve for either.
Jens Gustedt’s recommendation is that you declare a struct foo in the header but define it only in the C source file for the implementation and not in the header. A struct declared in this way is an incomplete type, and source code that can only see the declaration, and not the definition, cannot see what is in the type. It can, however, use pointers to the type.
The declaration of an incomplete struct may be as simple as struct foo. You can also define a type, such as typedef struct foo foo; or typedef struct foo Mytype;, and you can define a type that is a pointer to the struct, such as typedef struct foo *FooPointer;. However, these are merely for convenience. They do not alter the basic notion, that there is a struct foo that API users cannot see into but that they can have pointers to.
Inside the implementation, you would fully define the struct. If you want an unsigned int in the struct, you would use:
struct foo
{
unsigned int x;
};
In general, you define the struct foo to contain whatever data you like.
Since the API user cannot define struct foo, you must provide functions to create and destroy objects of this type as necessary. Thus, you would likely have a function declared as extern struct foo *FooAlloc(some parameters);. The function creates a struct foo object (likely by calling malloc or a related function), initializes it with data from the parameters, and returns a pointer to the object (or NULL if the creation or initialization fails). You would also have a function extern void FooFree(struct foo *p); that frees a struct foo object. You might also have functions to reset, set, or alter the state of a foo object, functions to copy foo objects, and functions to report about foo objects.
Your implementations could also define some global struct foo objects that could be visible (essentially by address only) to API users. As a matter of good design, this should be done only for certain special purposes, such as to provide instances of struct foo objects with special meanings, such as a constant object with a permanent “initial state” for copying.
Your two implementations, the “natural C” and the “optimized C” implementations may have different definitions for the struct foo, provided they are not both used in a program together. (That is, each entire program is compiled with one implementation or the other, not both. If necessary, you could mangle both into a program by using a union, but it is preferable to avoid that.)
This is not a singleton approach.
Just do
typedef struct foo foo;
These are two declarations, a forward declaration of a struct and a type alias with the same name. Forward declared struct can be used to nothing else than to define pointers to them. This should give you enough abstraction and type safety.
In all your interfaces you'd have
extern void proc(foo* a);
and you'd have to provide functions
extern foo* foo_alloc(size_t n);
extern void foo_free(foo* a);
This would bind your users as well as your library to always use the same struct. Thereby the implementation of foo is completely hidden to the API users. You could even one day to decide to use something different than a struct since users should use foo without the struct keyword.
Edit: Just a typedef to some kind of integer wouldn't help you much, because these are only aliases for types. All your types aliased to unsigned could be used interchangeably. One way around this would be to encapsulate them inside a struct. This would make your internal code a bit ugly, but the generated object code should be exactly the same with a good modern compiler.

Resources