I'm currently a bit confused regarding the concept of information hiding of C-structs.
The backround of this question is an embedded c project with nearly zero knowledge of OOP.
Up until now I always declared my typedef structs inside the header file of the corresponding module. So every module which wants to use this struct knows the struct type.
But after a MISRA-C check I discovered the medium severity warning: MISRAC2012-Dir-4.8 - The implementation of a structure is unnecessarily exposed to a translation unit.
After a bit of research I discovered the concept of information hiding of C-structs by limiting the visible access of the struct members to private scope.
I promptly tried a simple example which goes like this:
struct_test.h
//struct _structName;
typedef struct _structName structType_t;
struct_test.c
#include "struct_test.h"
typedef struct _structName
{
int varA;
int varB;
char varC;
}structType_t;
main.c
#include "struct_test.h"
structType_t myTest;
myTest.varA = 0;
myTest.varB = 1;
myTest.varC = 'c';
This yields the compiler error, that for main.c the size of myTest is unknown. And of course it is, main.c has only knowledge that a struct of the type structType_t exists and nothing else.
So I continued my research and stumbled upon the concept of opaque pointers.
So I tried a second attempt:
struct_test.h
typedef struct _structName *myStruct_t;
struct_test.c
#include "struct_test.h"
typedef struct _structName
{
int varA;
int varB;
char varC;
}structType_t;
main.c
#include "struct_test.h"
myStruct_t myTest;
myTest->varA = 1;
And I get the compiler error: dereferencing pointer to incomplete type struct _structName
So obviously I haven't understood the basic concept of this technique. My main point of confusion is where the data of the struct object will?
Up until now I had the understanding that a pointer usually points to a "physical" representation of the datatype and reads/writes the content on the corresponding address.
But with the method above, I declare a pointer myTest but never set an address where it should point to.
I took the idea from this post: What is an opaque pointer in C?
In the post it is mentioned, that the access is handled with set/get interface methods so I tried adding one similiar like this:
void setVarA ( _structName *ptr, int valueA )
{
ptr->varA = valueA;
}
But this also doesn't work because now he tells me that _structName
is unknown...
So can I only access the struct with the help of additional interface methods and, if yes, how can I achieve this in my simple example?
And my bigger question still remains where the object of my struct is located in memory. I only know the pointer concept:
varA - Address: 10 - Value: 1
ptrA - Address: 22 - Value: 10
But in this example I only have
myTest - Address: xy - Value: ??
I have trouble understanding where the "physical" representation of the corresponding myTest
pointer is located?
Furthermore I can not see the benefits of doing it like this in relatively small scope embedded projects where I am the producer and consumer of the modules.
Can someone explain me if this method is really reasonable for small to mid scale embedded projects with 1-2 developers working with the code? Currently it seems like more effort to make all this interface pointer methods than just declaring the struct in my header-file.
Thank you in advance
My main point of confusion is where the data of the struct object will?
The point is that you do not use the struct
representation (i.e. its size, fields, layout, etc.) in other translation units, but rather call functions that do the work for you. You need to use an opaque pointer for that, yes.
how can I achieve this in my simple example?
You have to put all the functions that use the struct fields (the real struct) in one file (the implementation). Then, in a header, expose only the interface (the functions that you want users to call, and those take an opaque pointer). Finally, users will use the header to call only those functions. They won't be able to call any other function and they won't be able to know what is inside the struct, so code trying to do that won't compile (that is the point!).
Furthermore I can not see the benefits of doing it like this in relatively small scope embedded projects where I am the producer and consumer of the modules.
It is a way to force modules to be independent of each other. Sometimes it is used to hide implementations to customers or to be able to guarantee ABI stability.
But yes, for internal usage, it is usually a burden (and hinders optimization, since everything becomes a black box to the compiler except if you use LTO etc.). A syntactic approach like public
/private
in other languages like C++ is way better for that.
However, if you are bound to follow MISRA to such degree (i.e. if your project has to follow that rule, even if it is only advisory), there is not much you can do.
Can someone explain me if this method is really reasonable for small to mid scale embedded projects with 1-2 developers working with the code?
That is up to you. There are very big projects that do not follow that advice and are successful. Typically a comment for private fields, or a naming convention, is enough.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With