multiple types in struct - C - c

I am new to C, and I am used to Java OOP. I have to use struct as holder for my global variables, that the system will write to/read from constantly.
I have 3 different types of variables in the struct, and I am not sure if that can cause a problem.
Also - do I need to declare the struct in the header file, in order to use it other C file ?
What will be the fastest and better way to access the variables from that struct in the different functions ? // The functions using these variables are in the same C file.
Here is the struct itself, that I made:
struct Data
{
double percentage_Height = 0;
double speed_Height = 0;
double time_Height = 0;
int distance_Height = 0;
double percentage_Distance = 0;
double speed_Distance = 0;
double time_Distance = 0;
int distance_Distance = 0;
uint16_t valueSpeed = 0;
double speedOfMotor = 0;
int tilt = 0;
};
and an example of a function that should use some of the fields of the struct:
int getHeight()
{
percentage_Height = getIncline()/90.0;
speed_Height = db_speed_sensor();
time_Height = 0.000027; // [h] , 100ms
distance_Height=0;
if (percentage_Height == 0)
{
percentage_Height = 1;
}
distance_Height = speed_Height * time_Height * percentage_Height * 100;
return distance_Height;
}
so what will be the best way to access these struct fields, instead of writing just the global vars?
EDIT: it is a real-time operating system, so tasks (smth like threads) will be accessing the data in the struct. I don't know if that makes any changes...

Define a global variable of type Data and access its members wherever you want.
struct Data GlobalData;
int getHeight()
{
GlobalData.percentage_Height = getIncline()/90.0;
GlobalData.speed_Height = db_speed_sensor();
....
}
If you want to use this in multiple files, better to define the structure in header file.

You have to declare the structure in a header file.
If an instance of this structure will be in the global scope, you have to define this instance in the global scope like this:
struct Data gData;
int getHeight()
{
gData.percentage_Height = getIncline()/90.0;
...
}
If your instance will be used only in the functions which are declared in the same file, you should define your variable like this:
static struct Data gData;
int getHeight()
{
gData.percentage_Height = getIncline()/90.0;
...
}
The keyword "static" means your variable is in the file scope (only visible in the file)

Yes, you should define the struct in a file and need to include it for its usage in other files. different datatypes in structure won't have any issue.
You can define functions separately to access the structure members and to process it. so that you don't need to repeat code. [ as like you did getHeight() ]. you can define those functions *inline*
to improve performance. (fastest way to access?) [only if the function is simple and (small in size)]
even you can use MACROS.
Use typedef for convenience.
typedef struct { ... } DATA;
so that code can be simplified. instead of writting
struct Data *s; simply put DATA *s;
you should use
s->structmember to process it.

Everyone has advised you to use a global structure. I would just like to add that, as you mentioned, all the functions accessing this structure are in one file, you should also declare a structure as static so that global structure will be limited file scope.

What will be the fastest and better way to access the variables from that struct in the different functions ? // The functions using these variables are in the same C file.
Using a pointer to that struct.
Example:
int getHeight(struct Data *data)
{
data->percentage_Height = getIncline()/90.0;
data->speed_Height = db_speed_sensor();
data->time_Height = 0.000027; // [h] , 100ms
data->distance_Height=0;
if (data->percentage_Height == 0)
{
data->percentage_Height = 1;
}
data->distance_Height = data->speed_Height * data->time_Height * data->percentage_Height * 100;
return data->distance_Height;
}
int main(int argc, char *argv[])
{
struct Data data;
load_data(&data); // function to initialize data
distance_Height = getHeight(&data);
return distance_Height;
}
Let the compiler decides when to inline those functions to improve performance, you should be worried about the readability and organization of your code.
Also - do I need to declare the struct in the header file, in order to use it other C file ?
If you want to direct access its members in other sources, you need to define it in a header, but you could just declare that you have that struct in you C, and create function to access the values of you struct. In this case you could define the struct only in the source file, and declare it in a header or any other source files you need this declaration.
Example:
file1:
#include <stdlib.h>
struct my_struct_s {
int value;
};
struct my_struct_s *create_my_struct(void)
{
return malloc(sizeof(struct my_struct_s));
}
void destroy_my_struct(struct my_struct_s *my_struct)
{
free(my_struct);
}
void set_my_struct(struct my_struct_s *my_struct, int value)
{
my_struct->value = value;
}
int get_my_struct(struct my_struct_s *my_struct)
{
return my_struct->value;
}
file 2:
#include <stdio.h>
#include <string.h>
struct my_struct_s;
struct my_struct_s *create_my_struct(void);
void destroy_my_struct(struct my_struct_s *my_struct);
void set_my_struct(struct my_struct_s *my_struct, int value);
int get_my_struct(struct my_struct_s *my_struct);
int main() {
struct my_struct_s *my_struct;
my_struct = create_my_struct();
set_my_struct(my_struct, 10);
printf("my_struct value = %d\n", get_my_struct(my_struct));
destroy_my_struct(my_struct);
return 0;
}
It would be better to have a header with the declarations needed to access the struct of file1, and include this header in file2, just made it this way to show you that it is possible, and maybe give you a clue about the difference between definition and declaration

A struct can hold any variety of types, no problem with how many variables you have in there as long as you have the memory for them.
You can declare a struct in a header file, but you will need to initialise it somewhere.
For example if you initialise it in a source file that is not your main and you still want to use it there, you will have to declare it in the main file with the keyword extern. Let me demonstrate:
file.h - a struct Foo is defined here
file.c - an instance of Foo named foo is initialised here with some values.
main.c - we want to use it here. In order to do that we put a statement for example right after the includes that reads extern struct Foo foo;
Or you can plain add file.h to your main.c file and just initialise it there.
Normally a struct variable is accessed like this: name_of_struct.member, e.g. struct.int_member = 42.
If you have a pointer to a struct and you try to modify the struct via the pointer there are two ways of doing this:
The more popular way:
ptr_to_struct->member = 42;
Or a more typical way for other types, but rather unusual in this case (at least for one level of dereference):
*ptr_to_struct.member = 42;
I would recommend that you pass the struct as an argument to the functions modifying it. Don't just use it as a plain global.

Related

Change type of variable to point to a different struct

I have a struct that change a field's type based on a version (variable):
typedef struct __base {
char count[10];
void *entry[10];
} Base;
typedef struct __base_16 {
u_int16 count[10];
void *entry[10];
} Base16;
void main() {
/* version is computed at runtime based on some parameters */
if (version >= 2) {
Base *b = malloc(sizeof(Base));
} else {
Base16 *b = malloc(sizeof(Base16));
}
b->count[0] = 10;
b->count[1] = 20;
}
Of course this code doesn't compile, what are clean alternative to be able to access the struct without using a void pointer and casting every access to the fields?
Per my comment: If the version value can set using a #define read from a header file it might be an idiomatic way to do this, eg. #defines are commonly used to define variations in how objects are defined for large code base project. Using this method, the struct would be built only one way based on #ifdef sections that determine how the struct will be defined. This approach allows for a more generic name for your typedef, from which it follows your code would only have to reference one name for all instances of the struct
//in environment setting or header file
#define BASE_16
//in source .c, or in .h
#ifdef BASE_16
typedef struct {
u_int16 count[10];
void *entry[10];
} count_t;//common name for all definitions, allowing for
//simpler references in code that uses it
#endif
#ifdef BASE_8
typedef struct {
u_int8 count[10];
void *entry[10];
} count_t;
#endif
#ifdef BASE_32
typedef struct {
u_int32 count[10];
void *entry[10];
} count_t;
#endif
As I understand, you would like to execute code, which looks the same for variables which have significantly distinct types, and write this code only once while the variable type is recognized at runtime?
I do not think, it is possible in C. Processor must execute significantly different instructions, so it must be reflected in the C code. I would propose to put all that identical code in a function, which gets your ‘changing-type-variable’ as an argument. Then copy this function in editor, and just change its name and argument type. Like this:
void func(Base *b)
{
b->count[0] = 10;
b->count[1] = 20;
...
}
void func16(Base16 *b)
{
b->count[0] = 10;
b->count[1] = 20;
...
}
void main() {
/* version is computed at runtime based on some parameters */
if (version >= 2) {
Base *b = malloc(sizeof(Base));
func(b);
} else {
Base16 *b16 = malloc(sizeof(Base16));
func16(b16);
}
}
Let me do a remark: In somehow opposite case, when coding for different types must be applied to the same space in memory, union works very well, like e.g.:
union count
{
char CNTC[10];
u_int16 CNT16[10];
} Count;

How to pass a pointer to a struct declared inside another struct as a function parameter?

In one of my applications written in C I have a struct declared as a member of another struct:
struct _test
{
int varA;
//...
struct _small
{
int varB;
//...
} small;
} test;
Now I want to create a function that access varB above, but I don't want it to access the entire structure test, that is, I don't want to do:
#include <relevant_header>
void myFunction()
{
test.small.varB = 0;
}
instead, I want to pass only the small structure as a parameter to that function; something like this:
#include <relevant_header>
void myFunction(struct _test::_small* poSmall)
{
poSmall->varB = 0;
}
The problem is I don't know how to do this, that is, the above code doesn't compile right (I suppose it's C++ syntax only). So how may I do this in a C code - pass a pointer to a struct that was declared inside another struct? I wasn't able to find anything about this both in SO as well as in Google in general.
Just do:
void myFunction(struct _small *poSmall)
{
poSmall->varB = 0;
}
The scope of struct _small is not limited to its outer structure.

Assign values to a struct

struct example{
int a;
int b;
};
in main.c
I can write to this struct in main.c as follows
struct example obj;
obj.a=12;
obj.b=13;
Is there a way that I can directly write to the global memory location of this struct, so that the values can be accessed anywhere across the program?
Two ways:
You can take it address and pass it as a parameters to the functions that needs to access this data
&obj
Or, use a global:
Outside of any function, write struct example obj;
And in a header declare:
struct example {
int a;
int b;
};
extern struct example obj;
Edit: Reading this issue might be a good idea: How do I use extern to share variables between source files?
There are two ways to accomplish this:
1.
Create a header file that contains the following statement:
/* header.h */
extern struct example obj;
Add the following definition to one and only one source file:
/* source.c */
struct example obj;
Any source file that needs direct access to obj should include this header file.
/* otherFile.c */
#include "header.h"
void fun(void)
{
obj.a = 12;
obj.b = 13;
}
2.
Create getter/setter functions:
/* source.c */
static struct example obj;
void set(const struct example * const pExample)
{
if(pExample)
memcpy(&obj, pExample, sizeof(obj));
}
void get(struct example * const pExample)
{
if(pExample)
memcpy(pExample, &obj, sizeof(obj));
}
/* otherFile.c */
void fun(void)
{
struct example temp = {.a = 12, .b = 13};
set(&temp);
get(&temp);
}
With this method, obj can be defined as static.
You can initialize it with a brace initializer, as in:
struct example obj = {12,13};
You could also declare a pointer to it, as in:
struct example* myPtr = &obj;
int new_variable = myPtr->a;
and then use that pointer to access the data members. I hope this addresses your question.

Good Coding Practice With C structs?

In C, you can define structures to hold an assortment of variables;
typedef struct {
float sp;
float K; // interactive form - for display only
float Ti; // values are based in seconds
float Td;
} pid_data_t;
But lets say that K, Ti, and Td should never be set publicly, and should only be used for storing the values after they have been manipulated. So, I want these values not to be updated by;
pid_data_t = pid_data;
pid_data.K = 10; // no good! changing K should be done via a function
I want them to be set via a function;
int8_t pid_set_pid_params(float new_K_dash, float new_Ti_dash,
float new_Td_dash)
{
… // perform lots of things
pid_data->K = new_K_dash;
pid_data->Ti = new_Ti_dash;
pid_data->Td = new_Td_dash;
}
Any thoughts on this? I know C++ uses like a get/set property, but was wondering what people might do on C.
Your public interface should only offer an opaque pointer (maybe DATA*, or data_handle), as well as handler functions create_data(), set_data_value(), read_data_value(), free_data(), etc., which operate on the opaque pointer.
Much like FILE*.
Just don't give your clients the internal header files :-)
// library.h
typedef struct data_t * data_handle;
data_handle create_data();
void free_data(data_handle);
Private implementation (don't ship):
#include "library.h"
struct data_t
{
/* ... */
};
data_handle create_data() { return malloc(sizeof(struct data_t)); }
void free_data(data_handle h) { free(h); }
/* etc. etc. */
in C, by convention....
for OO C like this...
I'd have a pid_data_create(&data) // initializes your struct
and pid_data_set_proportional_gain(&data, 0.1);
etc...
so basically achieving a C++ ish class... prefix all functions with the "class" / "struct" name and always pass the struct * as the first parameter.
also, it should store function pointers for polymorphisim, and you shouldn't call those function pointers directly, again, have a function that takes your struct as a parameter, and then the can make the function pointer call (can check for nulls, fake inheritance/virtual functions, and other stuff)
The canonical way to do this is by using a combination of opaque pointers and public structs, along with allocators, getters and setters for the private elements. About along these lines:
foo.h
typedef struct Foo {
/* public elements */
} Foo;
Foo *new_Foo(void);
void Foo_something_opaque(Foo* foo);
foo.c
#include "foo.h"
typedef struct Private_Foo_ {
struct Foo foo;
/* private elements */
} Private_Foo_;
Foo *new_Foo(void)
{
Private_Foo_ *foo = malloc(sizeof(Private_Foo_));
/* initialize private and public elements */
return (Foo*) foo;
}
void Foo_something_opaque(Foo *foo)
{
Private_Foo_ *priv_foo = (Private_Foo_*) foo;
/* do something */
}
This woks, because C guarantees, that the address of a struct variable always is equal to the address of the very first struct element. We can use this to have a Private_Foo_ struct, containing a public Foo at the beginning, giving out pointers to the whole thing, with the compilation units not having access to the Private_Foo_ struct defintion just seeing some memory without any context.
It should be noted that C++ works quite similar behind the curtains.
Update
As KereekSB pointed out, this will break if used in a array.
I say: Then don't make Foo f[], however tempting, but make an arrays of pointers to Foo: Foo *f[].
If one really insists on using it in arrays do the following:
foo_private.h
typedef struct Private_Foo_ {
/* private elements */
} Private_Foo_;
static size_t Private_Foo_sizeof(void) { return sizeof(Private_Foo_); }
foo_private.h is written in a way, that it can be compiled into an object file. Use some helper program to link it and use the result of Private_Foo_sizeof() to generate the actual, plattform dependent foo.h from some foo.h.in file.
foo.h
#include
#define FOO_SIZEOF_PRIVATE_ELEMENTS <generated by preconfigure step>
typedef struct Foo_ {
/* public elements */
char reserved[FOO_SIZEOF_PRIVATE_ELEMENTS];
} Foo;
Foo *new_Foo(void);
void Foo_something_opaque(Foo* foo);
foo.c
#include "foo.h"
#include "foo_private.h"
Foo *new_Foo(void)
{
Foo *foo = malloc(sizeof(Foo));
/* initialize private and public elements */
return (Foo*) foo;
}
void Foo_something_opaque(Foo *foo)
{
Private_Foo_ *priv_foo = (Private_Foo_*) foo.reserved;
/* do something */
}
IMHO this is really messy. Now I'm a fan of smart containers (unfortunately there's no standard container library for C). Anyway: In such a container is creates through a function like
Array *array_alloc(size_t sizeofElement, unsigned int elements);
void *array_at(Array *array, unsigned int index);
/* and all the other functions expected of arrays */
See the libowfaw for an example of such an implementation. Now for the type Foo it was trivial to provide a function
Array *Foo_array(unsigned int count);
Object orientation is a way of thinking and modelling, data encapsulation where struct data should not be modified directly by the user can be implemented this way:
my_library.h
#ifndef __MY_LIBRARY__
#define __MY_LIBRARY__
typedef void MiObject;
MyObject* newMyObject();
void destroyMyObject(MyObject*)
int setMyObjectProperty1(MyObject*,someDataType1*);
/*Return a pointer to the data/object, classic pass by value */
someDataType1* getMyObjectProperty2Style1(MyObject*);
int setMyObjectProperty2(MyObject*,someDataType2*);
/* The data/object is passed through reference */
int getMyObjectProperty2Style2(MyObject*,someDataType2**);
/* Some more functions here */
#endif
my_library.c
struct _MyHiddenDataType{
int a;
char* b;
..
..
};
MyObject* newMyObject(){
struct _MyHiddenData* newData = (struct _MyHiddenData*)malloc(sizeof(struct _MyHiddenData);
//check null, etc
//initialize data, etc
return (MyObject*)newData;
}
int setMyObjectProperty1(MyObject* object,someDataType1* somedata){
struct _MyHiddenData* data = (struct _MyHiddenData*)object;
//check for nulls, and process somedata
data->somePropery=somedata;
}
someDataType1* getMyObjectProperty2Style1(MyObject*){
struct _MyHiddenData* data = (struct _MyHiddenData*)object;
//check for nulls, and process somedata
return data->someProperty;
}
/* Similar code for the rest */
And this way you have encapsulated the struct properties as if they were private. On the same manner static functions inside my_libray.c would behave as private functions. Get a good look at C and you'll see, that your imagination is the limit to what you can do.

Hiding members in a C struct

I've been reading about OOP in C but I never liked how you can't have private data members like you can in C++. But then it came to my mind that you could create 2 structures. One is defined in the header file and the other is defined in the source file.
// =========================================
// in somestruct.h
typedef struct {
int _public_member;
} SomeStruct;
// =========================================
// in somestruct.c
#include "somestruct.h"
typedef struct {
int _public_member;
int _private_member;
} SomeStructSource;
SomeStruct *SomeStruct_Create()
{
SomeStructSource *p = (SomeStructSource *)malloc(sizeof(SomeStructSource));
p->_private_member = 42;
return (SomeStruct *)p;
}
From here you can just cast one structure to the other.
Is this considered bad practice? Or is it done often?
sizeof(SomeStruct) != sizeof(SomeStructSource). This will cause someone to find you and murder you someday.
Personally, I'd more like this:
typedef struct {
int _public_member;
/*I know you wont listen, but don't ever touch this member.*/
int _private_member;
} SomeStructSource;
It's C after all, if people want to screw up, they should be allowed to - no need to hide stuff, except:
If what you need is to keep the ABI/API compatible, there's 2 approaches that's more common from what I've seen.
Don't give your clients access to the struct, give them an opaque handle (a void* with a pretty name), provide init/destroy and accessor functions for everything. This makes sure you can change
the structure without even recompiling the clients if you're writing a library.
provide an opaque handle as part of your struct, which you can allocate however you like. This approach is even used in C++ to provide ABI compatibility.
e.g
struct SomeStruct {
int member;
void* internals; //allocate this to your private struct
};
You almost have it, but haven't gone far enough.
In the header:
struct SomeStruct;
typedef struct SomeStruct *SomeThing;
SomeThing create_some_thing();
destroy_some_thing(SomeThing thing);
int get_public_member_some_thing(SomeThing thing);
void set_public_member_some_thing(SomeThing thing, int value);
In the .c:
struct SomeStruct {
int public_member;
int private_member;
};
SomeThing create_some_thing()
{
SomeThing thing = malloc(sizeof(*thing));
thing->public_member = 0;
thing->private_member = 0;
return thing;
}
... etc ...
The point is, here now consumers have no knowledge of the internals of SomeStruct, and you can change it with impunity, adding and removing members at will, even without consumers needing to recompile. They also can't "accidentally" munge members directly, or allocate SomeStruct on the stack. This of course can also be viewed as a disadvantage.
I do not recommend using the public struct pattern. The correct design pattern, for OOP in C, is to provide functions to access every data, never allowing public access to data. The class data should be declared at the source, in order to be private, and be referenced in a forward manner, where Create and Destroy does allocation and free of the data. In a such way the public/private dilemma won't exist any more.
/*********** header.h ***********/
typedef struct sModuleData module_t'
module_t *Module_Create();
void Module_Destroy(module_t *);
/* Only getters and Setters to access data */
void Module_SetSomething(module_t *);
void Module_GetSomething(module_t *);
/*********** source.c ***********/
struct sModuleData {
/* private data */
};
module_t *Module_Create()
{
module_t *inst = (module_t *)malloc(sizeof(struct sModuleData));
/* ... */
return inst;
}
void Module_Destroy(module_t *inst)
{
/* ... */
free(inst);
}
/* Other functions implementation */
In the other side, if you do not want to use Malloc/Free (which can be unnecessary overhead for some situations) I suggest you hide the struct in a private file. Private members will be accessible, but that on user's stake.
/*********** privateTypes.h ***********/
/* All private, non forward, datatypes goes here */
struct sModuleData {
/* private data */
};
/*********** header.h ***********/
#include "privateTypes.h"
typedef struct sModuleData module_t;
void Module_Init(module_t *);
void Module_Deinit(module_t *);
/* Only getters and Setters to access data */
void Module_SetSomething(module_t *);
void Module_GetSomething(module_t *);
/*********** source.c ***********/
void Module_Init(module_t *inst)
{
/* perform initialization on the instance */
}
void Module_Deinit(module_t *inst)
{
/* perform deinitialization on the instance */
}
/*********** main.c ***********/
int main()
{
module_t mod_instance;
module_Init(&mod_instance);
/* and so on */
}
Never do that. If your API supports anything that takes SomeStruct as a parameter (which I'm expecting it does) then they could allocate one on a stack and pass it in. You'd get major errors trying to access the private member since the one the compiler allocates for the client class doesn't contain space for it.
The classic way to hide members in a struct is to make it a void*. It's basically a handle/cookie that only your implementation files know about. Pretty much every C library does this for private data.
Something similar to the method you've proposed is indeed used sometimes (eg. see the different varities of struct sockaddr* in the BSD sockets API), but it's almost impossible to use without violating C99's strict aliasing rules.
You can, however, do it safely:
somestruct.h:
struct SomeStructPrivate; /* Opaque type */
typedef struct {
int _public_member;
struct SomeStructPrivate *private;
} SomeStruct;
somestruct.c:
#include "somestruct.h"
struct SomeStructPrivate {
int _member;
};
SomeStruct *SomeStruct_Create()
{
SomeStruct *p = malloc(sizeof *p);
p->private = malloc(sizeof *p->private);
p->private->_member = 0xWHATEVER;
return p;
}
I'd write a hidden structure, and reference it using a pointer in the public structure. For example, your .h could have:
typedef struct {
int a, b;
void *private;
} public_t;
And your .c:
typedef struct {
int c, d;
} private_t;
It obviously doesn't protect against pointer arithmetic, and adds a bit of overhead for allocation/deallocation, but I guess it's beyond the scope of the question.
There are better ways to do this, like using a void * pointer to a private structure in the public struct. The way you are doing it you're fooling the compiler.
Use the following workaround:
#include <stdio.h>
#define C_PRIVATE(T) struct T##private {
#define C_PRIVATE_END } private;
#define C_PRIV(x) ((x).private)
#define C_PRIV_REF(x) (&(x)->private)
struct T {
int a;
C_PRIVATE(T)
int x;
C_PRIVATE_END
};
int main()
{
struct T t;
struct T *tref = &t;
t.a = 1;
C_PRIV(t).x = 2;
printf("t.a = %d\nt.x = %d\n", t.a, C_PRIV(t).x);
tref->a = 3;
C_PRIV_REF(tref)->x = 4;
printf("tref->a = %d\ntref->x = %d\n", tref->a, C_PRIV_REF(tref)->x);
return 0;
}
Result is:
t.a = 1
t.x = 2
tref->a = 3
tref->x = 4
I found that bit-field might be a good solution if you really want to hide something.
struct person {
unsigned long :64;
char *name;
int age;
};
struct wallet {
char *currency;
double balance;
};
The first member of struct person is an unnamed bit-field. used for a 64-bit pointer in this case. It's completely hidden and cannot be accessed by struct variable name.
Because of the first 64-bit in this struct is unused, so we can use it as a private pointer. We can access this member by its memory address instead of variable name.
void init_person(struct person* p, struct wallet* w) {
*(unsigned long *)p = (unsigned long)w;
// now the first 64-bit of person is a pointer of wallet
}
struct wallet* get_wallet(struct person* p) {
return (struct wallet*)*(unsigned long *)p;
}
A small working example, tested on my intel mac:
//
// Created by Rieon Ke on 2020/7/6.
//
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#if __x86_64__ || __LP64__
#define PRIVATE_SET(obj, val) *(unsigned long *) obj = (unsigned long) val;
#define PRIVATE_GET(obj, type) (type)*(unsigned long *) obj;
#define PRIVATE_POINTER unsigned long:64
#else
#define PRIVATE_SET(obj, val) *(unsigned int *) obj = (unsigned int) val;
#define PRIVATE_GET(obj, type) (type)*(unsigned int *) obj;
#define PRIVATE_POINTER unsigned int:32
#endif
struct person {
PRIVATE_POINTER;
char *name;
int age;
};
struct wallet {
char *currency;
double balance;
};
int main() {
struct wallet w;
w.currency = strdup("$$");
w.balance = 99.9;
struct person p;
PRIVATE_SET(&p, &w) //set private member
p.name = strdup("JOHN");
p.age = 18;
struct wallet *pw = PRIVATE_GET(&p, struct wallet*) //get private member
assert(strcmp(pw->currency, "$$") == 0);
assert(pw->balance == 99.9);
free(w.currency);
free(p.name);
return 0;
}
This approach is valid, useful, standard C.
A slightly different approach, used by sockets API, which was defined by BSD Unix, is the style used for struct sockaddr.
My solution would be to provide only the prototype of the internal struct and then declare the definition in the .c file. Very useful to show C interface and use C++ behind.
.h :
struct internal;
struct foo {
int public_field;
struct internal *_internal;
};
.c :
struct internal {
int private_field; // could be a C++ class
};
Note: In that case, the variable have to be a pointer because the compiler is unable to know the size of the internal struct.
Not very private, given that the calling code can cast back to a (SomeStructSource *). Also, what happens when you want to add another public member? You'll have to break binary compatibility.
EDIT: I missed that it was in a .c file, but there really is nothing stopping a client from copying it out, or possibly even #includeing the .c file directly.
Related, though not exactly hiding.
Is to conditionally deprecate members.
Note that this works for GCC/Clang, but MSVC and other compilers can deprecate too,
so its possible to come up with a more portable version.
If you build with fairly strict warnings, or warnings as errors, this at least avoids accidental use.
// =========================================
// in somestruct.h
#ifdef _IS_SOMESTRUCT_C
# if defined(__GNUC__)
# define HIDE_MEMBER __attribute__((deprecated))
# else
# define HIDE_MEMBER /* no hiding! */
# endif
#else
# define HIDE_MEMBER
#endif
typedef struct {
int _public_member;
int _private_member HIDE_MEMBER;
} SomeStruct;
#undef HIDE_MEMBER
// =========================================
// in somestruct.c
#define _IS_SOMESTRUCT_C
#include "somestruct.h"
SomeStruct *SomeStruct_Create()
{
SomeStructSource *p = (SomeStructSource *)malloc(sizeof(SomeStructSource));
p->_private_member = 42;
return (SomeStruct *)p;
}
An anonymous struct can be of use here.
#ifndef MYSTRUCT_H
#define MYSTRUCT_H
typedef struct {
int i;
struct {
int j;
} MYSTRUCT_PRIVATE;
// NOTE: Avoid putting public members after private
int k;
} MyStruct;
void test_mystruct();
#endif
In any file that should have access to the private members, define MYSTRUCT_PRIVATE as an empty token before including this header. In those files, the private members are in an anonymous struct and can be accessed using m.j, but in all other places they can only be accessed using m.MYSTRUCT_PRIVATE.j.
#define MYSTRUCT_PRIVATE
#include "mystruct.h"
void test_mystruct() {
// Can access .j without MYSTRUCT_PRIVATE in both
// initializer and dot operator.
MyStruct m = { .i = 10, .j = 20, .k = 30 };
m.j = 20;
}
#include <stdio.h>
#include "mystruct.h"
int main() {
// You can declare structs and, if you jump through
// a small hoop, access private members
MyStruct m = { .i = 10, .k = 30 };
m.MYSTRUCT_PRIVATE.j = 20;
// This will not work
//MyStruct m2 = { .i = 10, .j = 20, .k = 30 };
// But this WILL work, be careful
MyStruct m3 = { 10, 20, 30 };
test_mystruct();
return 0;
}
I do not recommend putting public members after private members. Initializing a struct without member designators, such as with { 10, 20, 30 } can still initialize private members. If the number of private members changes, this will also silently break all initializers without member designators. It's probably best to always use member designators to avoid this.
You must design your structs, and especially the private members, to be zero initialized since there are no automatic constructors as in C++. As long as the members are initialized to 0 then they won't be left in an invalid state even without an initialization function. Barring a member designator initialization, initializing to simply { 0 } should be designed to be safe.
The only downside I've found is that this does mess with things like debuggers and code completion, they typically don't like it when one type has one set of members in one file, and a different set in another file.
Here's a very organized way to do it using macros. This is how I've seen it used in some of the big projects. I will assume the following:
Header file with the struct
Source file with access to private fields
Source file with no access to private fields (the fields exist but are renamed).
Header file:
// You can put this part in a header file
// and share it between multiple header files in your project
#ifndef ALLOW_PRIVATE_ACCESS
#define PRIVATE(T) private_##T
#else
#define PRIVATE(T) T
#endif
#define PUBLIC(T) T
typedef struct {
int PRIVATE(m1); // private member
int PUBLIC(m2); // public member
} mystruct;
mystruct *mystruct_create(void);
int mystruct_get_m1(mystruct *t);
Source file with access to private fields:
#include <stdlib.h>
#define ALLOW_PRIVATE_ACCESS
#include "mystruct.h"
mystruct *mystruct_create(void) {
mystruct *p = (mystruct *)malloc(sizeof(mystruct));
p->m1 = 42; // works (private)
p->m2 = 34; // works (public)
return (mystruct *)p;
}
int mystruct_get_m1(mystruct *t) {
return t->m1; // works (private)
}
Source file with no access to private fields:
#include <stdio.h>
#include <stdlib.h>
#include "mystruct.h"
int main() {
mystruct *t = mystruct_create();
printf("t->m1 = %d\n", t->m1); // error (private)
printf("t->m1 = %d\n", mystruct_get_m1(t)); // works (using function)
printf("t->m2 = %d\n", t->m2); // works (public)
free(t);
return 0;
}

Resources