Reputation: 3034
Consider the following struct defined in ModuleA:
typedef struct{
int A;
int B;
int C[4];
}myStructType;
myStructType MyStruct;
If I wanted to use this struct from ModuleB, then I would declare the struct in the ModuleA header like this:
extern myStructType MyStruct;
So far, so good. Other modules can read and write MyStruct by including the Module A header file.
Now the question:
How can I declare only part of the struct in the Module A header file? For example, if I wanted ModuleB to be able to read and write MyStruct.C (or, to make things a bit easier, perhaps MyStruct.A or MyStruct.B), but not necessarily know that it's in a struct or know about elements A and B.
Edit: I should probably also specify that this will go in an embedded system which does basically all of its memory allocation at compile time, so we can be extremely confident at compile time that we know where MyStruct is located (and it's not going to move around).
Edit2: I'll also clarify that I'm not necessarily trying to prevent other modules from accessing parts of the struct, but rather, I'm attempting to allow other modules to access individual elements without having to do MyStruct.Whatever because other modules probably only care about a single element and not the whole structure.
Upvotes: 2
Views: 223
Reputation: 70931
If it not for hiding but for structuring, then do structure it. For example like so:
moduleA.h:
typedef struct{
int A;
}myStructModuleAType;
extern myStructModuleAType myStructModuleA;
moduleA.c:
myStructModuleAType myStructModuleA;
moduleB.h:
typedef struct{
int B;
}myStructModuleBType;
extern myStructModuleBType myStructModuleB;
moduleB.c:
myStructModuleBType myStructModuleB;
main.h:
#include "moduleA.h"
#include "moduleB.h"
typedef struct{
myStructModuleAType * pmyStructModuleA;
myStructModuleBType * pmyStructModuleB;
int C[4];
}myStructType;
extern myStructType myStruct;
main.c:
#include "main.h"
myStructType myStruct;
myStructType myStruct = {
.pmyStructModuleA = &myStructModuleA
.pmyStructModuleB = &myStructModuleB
};
Upvotes: 0
Reputation: 62048
While in theory there might be some problems with the cleanliness of this solution (e.g. structure alignment), in practice it usually works if it compiles and if it doesn't compile, you can alter the structures to make it compile:
#include <stddef.h>
#define C_ASSERT(expr) extern char CAssertExtern[(expr)?1:-1]
// You keep this definition private to module A (e.g. in a .c file):
typedef struct
{
int A;
int B;
int C[4];
} PrivateStruct;
// You expose this definition to all modules (in an .h file):
typedef struct
{
char reserved[2*sizeof(int)];
int C[4];
} PublicStruct;
// You put these in module A (in a .c file):
C_ASSERT(sizeof(PrivateStruct) == sizeof(PublicStruct));
C_ASSERT(offsetof(PrivateStruct,C) == offsetof(PublicStruct,C));
int main(void)
{
return 0;
}
In the public .h file you can lie to the world about the global variable type:
extern PublicStruct MyStruct; // It's "PrivateStruct MyStruct;" in module A
If the two structure definitions go out of sync, you get a compile-time error (match, mismatch).
You will need to manually define the size of the reserved part of PublicStruct
, perhaps by trial and error.
You get the idea.
Upvotes: 2
Reputation: 32398
You can't do exactly what you've described but it's common to have a struct used as a header, which is contiguous with a buffer which has it's internals only known to a particular module.
It's fairly obvious what this struct is the header for, but it still works as an example:
typedef struct _FILE_NOTIFY_INFORMATION {
ULONG NextEntryOffset;
ULONG Action;
ULONG NameLength;
ULONG Name[1];
} FILE_NOTIFY_INFORMATION, *PFILE_NOTIFY_INFORMATION;
This struct (from Microsofts NativeSDK) is designed to be the header of a variable length buffer. All modules can work out how long the buffer is by looking at NameLength but you could use this method to store anything in the buffer which goes with it. That might only be known by a particular module with the others just using the length to copy it etc..
Upvotes: 0
Reputation: 4178
You could try to use a kind of getter:
in ModuleA:
typedef struct{
int A;
int B;
int C[4];
}myStructType;
myStructType MyStruct;
int getA()
{
return MyStruct.A;
}
and so on.
Instead switch over to c++
Upvotes: 1
Reputation: 399813
You would have to encapsulate it, i.e. make a private variable such as:
static myStructType the_struct;
in some C file, and then provide an API to get access to the parts:
int * getC(void)
{
return the_struct.C;
}
this would then let other C files get access to an integer array by calling
int *some_c = getC();
some_c[0] = 4711;
or whatever. It can be made "tighter" by being more explicit about the length of the returned array of course, I aimed for the minimal solution.
Upvotes: 3
Reputation: 143081
To make the long story short — you can't. To make it a bit longer, you can't reliably do it.
Upvotes: 1