Plain "C" static initializer macro with variable length tail. - c

I have a struct defined as:
typedef struct coro_context {
int id;
jmp_buf env;
list_head list;
jmp_buf waiter;
long timeout;
void *private;
char stack[0];
} coro_context;
which I need to initialize with three values
id = 0
private = function pointer
append to end of struct a suitable char array of length size
My current attempt looks like (the "unsigned long" bit is to get the right alignment):
#define CORO_CONTEXT(name,size) \
unsigned long __##name##_ctx[(sizeof(coro_context)+size)/sizeof(unsigned long)]={0};\
coro_context *name##_ctx = (coro_context *)__##name##_ctx
This works, but has two problems (ok, problems are one and a half ;) ):
it is UGLY (half problem).
I see no way to statically initialize private = name.
Note: I insist on "static initialization" because I want to use this in plain "C" (c11 is ok, if required) because I need to use these initialization outside function context.

I'd use a union overlaying the struct coro_context instance with a char buffer:
#include <setjmp.h>
typedef struct coro_context {
int id;
jmp_buf env;
list_head list;
jmp_buf waiter;
long timeout;
void *private;
char stack[]; /*should be [] in C11, [0] is not valid C */
} coro_context;
/*shouldn't start globals with underscore*/
/*shouldn't violate aliasing rules*/
/*C11 compound literals obviate the need for an extra global identifier*/
#define CORO_CONTEXT(name,size) \
coro_context *name##_ctx = &(union { coro_context ctx; char buf[sizeof(coro_context)+size]; }){ .ctx={ .private=&name } }.ctx;
int my_name;
CORO_CONTEXT(my_name,32)
and then take the address of .ctx. That should also get rid off the aliasing issues your solution has.
You'll need to initialize with an address of a global, because the value of a global is not usable in static initializations.
If you want something C99 compatible, you will need the extra identifier, but it shouldn't start with two underscores:
#include <setjmp.h>
typedef struct coro_context {
int id;
jmp_buf env;
list_head list;
jmp_buf waiter;
long timeout;
void *private;
char stack[1]; /*c99 doesn't have flexible array members*/
} coro_context;
#define CORO_CONTEXT(name,size) \
union { coro_context ctx; char buf[sizeof(coro_context)+size]; } name##_ctx__ = { { 0, {0},{0},{0}, 0, &name } }; \
coro_context *name##_ctx = &name##_ctx__.ctx;
int my_name;
CORO_CONTEXT(my_name,32)

First note that the size of the long buffer, may not match what you expect,as it is rounded to floor. for example if core_context size is 10 bytes, and one requested additional size of 3 bytes, and assuming long size is 8 bytes. you get (10+3)/8 = 1, so you allocate 1 long for handling 13 bytes (instead of allocating 2 longs).
so instead of
unsigned long __##name##_ctx[(sizeof(coro_context)+size)/sizeof(unsigned long)]={0};
I think it shall be
unsigned long __##name##_ctx[(sizeof(coro_context)+size+sizeof(unsigned long))/sizeof(unsigned long)]={0};
now regarding the static initialization, I wouldn't use long buffer, but create a new struct with the same first n variables, and with the requested sized buffer at end. this struct can be initialized statically, and the requested pointer will point to it. so the code would look like this:
#define CORO_CONTEXT(name,size,my_private_method) \
typedef struct coro_context##_name {\
int id;\
jmp_buf env;\
list_head list;\
jmp_buf waiter;\
long timeout;\
void *private;\
char stack[0];\
char additional_buffer[size];\
} coro_context##name;\
coro_context##name __name##_ctx = {0,0,0,0,0,my_private_method};\
coro_context *name##_ctx = (coro_context *)&__name##_ctx
for sake of simplicity, you can examine also this code using simplified struct, and using the coro_context struct as "base" of the wrapper struct (i.e. single variable instead of declaring all coro_context variables):
typedef struct coro_context {
int id;
void *private;
} coro_context;
#define DECLARE_CORO_CONTEXT(size,private_method)\
typedef struct wrapper_for_core_context\
{\
coro_context base;\
char buffer[size];\
}wrapper;\
wrapper my_wrapper = { {0, private_method}, 0 };\
coro_context *cc = (coro_context *)&my_wrapper;
//now the using code
DECLARE_CORO_CONTEXT( 20, test_at_avro_bytes_field_all_data_values );

Related

manage similar structs, one with arrays, the other with pointers

I have some structs containing arrays
struct mystruct_withArrays {
int foo;
int bar[MaxN];
int baz[MaxM];
}
and their equivalent with pointers
struct mystruct_withPointers {
int foo;
int *bar;
int *baz;
}
and I want to avoid the double definition. This is I want to make something as a template
#define myStruct(M,N)
...
such that myStruct(MaxM,MaxN) produces the array struct and myStruct(,) produces the struct with pointers.
Moreover, of course I want to do the same technique for multiple structs and to have automatic mapping from arrays to pointers. A final use case could be as follow
#include "mystructs.h"
//globals, for huge space usage
struct myStructA(1000,10000) hugeA;
struct myStructB(1024*1024) * hugeB;
void main(){
struct myStructA(,) smallA;
struct myStructB() smallB;
mapStruct(hugeA,smallA) //this is a macro
mapStruct(hugeB,smallB) //this is a macro
doSomething(smallA);
doSomethingMore(smallA,smallB);
doSomethingDetailed(smallB.qux);
}
where mapStruct(hugeA, smallA) is the obvious mapping smallA.bar = hugeA.bar, etc. The expanded code would be:
struct myStructA(1000,10000) hugeA;
struct myStructB(1024*1024) hugeB;
struct mystructA_withArrays {
int foo;
int bar[1000];
int baz[10000];
} hugeA;
struct mystructB_withArrays * {
int qux[1048576];
int quux[1048576];
} hugeB;
void main(){
struct mystructA_withPointers {
int foo;
int * bar;
int * baz;
} smallA;
struct mystructB_withArrays {
int * qux;
int * quxx;
} smallB;
smallA.bar=hugeA.bar;
smallA.baz=hugeA.baz;
smallB.qux=hugeB.qux;
smallB.quxx=hugeB.quxx;
doSomething(smallA);
doSomethingMore(smallA,smallB);
doSomethingDetailed(smallB.qux);
}
As you can see, the general idea is that some variables are allocated outside of the stack, but still without using malloc, just declaring them as globals. Even in some use case they are external globals from a linked shared object.
EDIT:
about memory performance, it is not easy to ascertain if malloc structs are better or worse than global struct. It depends also on the flag -mcmodel of the compiler
The sensible KISS solution seems to be this:
struct mystruct {
int foo;
int *bar;
int *baz;
};
struct mystruct array =
{
.bar = (int[ 1000]){0},
.baz = (int[10000]){0},
};
struct mystruct pointers;
Now the interface of this struct is the same no matter how data was allocated and "array structs" are 100% compatible with "pointer structs". If declared at file scope, the allocation of the compound literals will end up in .bss, same deal as in your pseudo code.
A possible solution to create several similar structures might be the use of an X macro.
(Unlike the Wikipedia page, I pass the macro X as an argument instead of redefining the macro.)
I edited the code a bit to add the assignments of the arrays to the corresponding pointers. I used variadic macros to allow omitting the variable names in the argument list. This is to show the concept, there may be room for improvement.
Example file macro.c
#define LIST_OF_ARRAY_FIELDS_1(X, ...) \
X(int, bar, MaxN, __VA_ARGS__) \
X(int, baz, MaxM, __VA_ARGS__)
#define LIST_OF_ARRAY_FIELDS_2(X, ...) \
X(char, bla1, MaxK, __VA_ARGS__) \
X(char, bla2, MaxL, __VA_ARGS__)
#define CREATE_ARRAY_FIELD(type, name, size, ...) \
type name[size];
#define CREATE_POINTER_FIELD(type, name, size, ...) \
type *name;
struct mystruct_withArrays {
int foo;
LIST_OF_ARRAY_FIELDS_1(CREATE_ARRAY_FIELD)
}
struct mystruct_withPointers {
int foo;
LIST_OF_ARRAY_FIELDS_1(CREATE_POINTER_FIELD)
}
struct otherstruct_withArrays {
int foo;
LIST_OF_ARRAY_FIELDS_2(CREATE_ARRAY_FIELD)
}
struct otherstruct_withPointers {
int foo;
LIST_OF_ARRAY_FIELDS_2(CREATE_POINTER_FIELD)
}
mystruct_withArrays hugeA;
mystruct_withPointers smallA;
otherstruct_withArrays hugeB;
otherstruct_withPointers smallB;
#define ASSIGN_POINTERS(type, name, size, dest, src) \
dest.name = src.name;
LIST_OF_ARRAY_FIELDS_1(ASSIGN_POINTERS, smallA, hugeA)
LIST_OF_ARRAY_FIELDS_2(ASSIGN_POINTERS, smallB, hugeB)
Result:
$ gcc -E macro.c
# 1 "macro.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "macro.c"
# 15 "macro.c"
struct mystruct_withArrays {
int foo;
int bar[MaxN]; int baz[MaxM];
}
struct mystruct_withPointers {
int foo;
int *bar; int *baz;
}
struct otherstruct_withArrays {
int foo;
char bla1[MaxK]; char bla2[MaxL];
}
struct otherstruct_withPointers {
int foo;
char *bla1; char *bla2;
}
mystruct_withArrays hugeA;
mystruct_withPointers smallA;
otherstruct_withArrays hugeB;
otherstruct_withPointers smallB;
smallA.bar = hugeA.bar; smallA.baz = hugeA.baz;
smallB.bla1 = hugeB.bla1; smallB.bla2 = hugeB.bla2;

What does "typedef char A[max_size]" means?

I have this portion of code and I don't understand how the first typedef works and what happen when we use it in the struct.
#define MAX_BLOCKEDADDRESS_SIZE 256
typedef char BlockedAddress[MAX_BLOCKEDADDRESS_SIZE];
typedef struct Blocked {
int capacity;
int length;
BlockedAddress *mailAddress;
} Blocked;
BlockedAddress is a user defined type that is a 256 char array.
#define MAX_BLOCKEDADDRESS_SIZE 256
typedef char BlockedAddress[MAX_BLOCKEDADDRESS_SIZE];
Blocked is a user defined type, a struct containing 2 int and one pointer members.
typedef struct Blocked {
int capacity;
int length;
BlockedAddress *mailAddress;
} Blocked;
The member mailAddress is a pointer to BlockedAddress.
mailAddress as pointer to array 256 of char

open addressing collision resolution

I faced a difficulty while implementing open addressing hash table in the c programming language:
#ifndef COMDS_OPENADDR_HASH_TABLE
#define COMDS_OPENADDR_HASH_TABLE
#define COMDS_KEY_EXIST 1
#define COMDS_REALLOC_FAIL 2
struct kv_pairs {
void *key;
void *value;
};
typedef struct openaddr_hash_table {
size_t buckets;
size_t used;
size_t (*hash)(void *data);
struct kv_pairs *table;
int (*key_equal)(void *fkey, void *skey);
int (*value_equal)(void *fvalue, void *svalue);
}OpenAddrHashTable;
#endif
So here I use a array of struct kv_pairs, to hold my keys and value, the problem is that i must have 3 special values: DELETED, USED, FREE to indicate that the location is deleted/used/free, I don't know how to encode these value?
I tried to set struct kv_pairs able and set FREE 0x0 DELETED 0x1 and USED 0x2, and doing the comparison like that
table[i] == FREE || table[i] == (struct kv*)DELETED
The question is a bit confusing and I'm supposing that you're not trying to access already freed memory (which your question makes me think you are).
Adding an enum tag to struct kv_pair would be an easy solution
struct kv_pair {
enum { KV_PAIR_FREE, KV_PAIR_DELETED, KV_PAIR_USED } tag;
void *key;
void *value;
};
Or you could add a separate array (possibly allocated together) of tags to struct openaddr_hash_table
enum tag { KV_PAIR_FREE, KV_PAIR_DELETED, KV_PAIR_USED};
struct openaddr_hash_table {
size_t buckets;
size_t used;
size_t (*hash)(void *data);
struct kv_pairs *table;
enum tag *tags;
int (*key_equal)(void *fkey, void *skey);
int (*value_equal)(void *fvalue, void *svalue);
};
The one to choose would depend on the common memory access pattern, but both would increase the memory usage of the data structure. A third solution with no memory increase (that seems to be what you want) could be the following:
#include <stdint.h>
#define FREE 0
#define DELETED 1
struct kv_pair {
void *key;
union {
void *value;
uintptr_t tag;
} value;
};
You would check the tag only if key is NULL and if not, it's in use.

C dynamic array initialization problem

I'm having a problem initializing an array of structs in my C program. Here's the function where it gets initialized:
void InitializeBPStructures() {
SatCounterTable = (struct SatCounterTableEntry *)malloc(sizeof(struct SatCounterTableEntry) * Counter_Count);
}
Counter_Count is an integer global variable and SatCounterTable is declared earlier in the C source file as
static struct SatCounterTableEntry* SatCounterTable;
and if it's relevant this is my SatCounterTable struct
struct SatCounterTableEntry {
enum SatCounter_State Predict_State;
md_addr_t tag;
};
md_addr_t is just a label for an unsigned int corresponding to a memory address
The problem is that when I try and compile, I get the following error
sim-safe.c:129: error: expected expression before ‘=’ token
And the array initialization in my IntitializeBPStructures() is on line 129. I'm not sure why this line is a problem. Any ideas?
EDIT:
Here's some additional lines of code around the function
struct SatCounterTableEntry
{
enum SatCounter_State Predict_State;
md_addr_t tag;
};
/* simulated registers */
static struct regs_t regs;
/* simulated memory */
static struct mem_t *mem = NULL;
/* track number of refs */
static counter_t sim_num_refs = 0;
/* maximum number of inst's to execute */
static unsigned int max_insts;
static struct SatCounterTableEntry* SatCounterTable;
void InitializeBPStructures()
{
SatCounterTable = (struct SatCounterTableEntry *)malloc(sizeof(struct SatCounterTableEntry) * Counter_Count);
}
void BranchPredict(md_addr_t PC, md_addr_t nextPC, enum Branch_Result result)
{
if (result == N)
sim_num_mispred_static++;
if (result != (myrand() % 2))
sim_num_mispred_random++;
sim_num_br++;
}
You're missing a semicolon at line 126.
Edit: new idea
Do you perhaps have a #define with an extra =?
#define Counter_Count = 42; /* WRONG */
#define Counter_Count = 42 /* WRONG */
#define Counter_Count 42; /* WRONG, but it works some time */
#define Counter_Count 42 /* CORRECT */
SatCounterTable is declared earlier in the C source file as
static struct SatCounterTableEntry* SatCounterTable;
Is that declaration made at file scope or is it within another function? If the latter, then the SatCounterTable name won't be visible inside InitializeBPStructures().
SatCounterTable = (struct SatCounterTableEntry *)malloc(sizeof(struct SatCounterTableEntry) * Counter_Count);
Ugh. Do me a favor and rewrite that as
SatCounterTable = malloc(sizeof *SatCounterTable * Counter_Count);
You really don't need to cast the result of malloc(); that hasn't been necessary since C89 was adopted. And using sizeof on the object being allocated rather than the type can save you some heartburn (if nothing else, it saves some keystrokes).
The error text suggests that something hasn't been defined properly prior to this call; for some reason it isn't recognizing SatCounterTable. I think pmg's on the right track. You must be missing a semicolon or a curly bracket or something prior to this call.
The C compiler you are using has some reason to believe that SatCounterTable is not an lvalue or primary expression. Given how your variables are named (confusingly I might add), is it possible that you defined a variable at a closer scope also with the name SatCounterTable, such that SatCounterTable is not an assignable expression?
Edit: I would also seriously consider pmg's answer.
I compiled this code:
#include <stdlib.h>
typedef unsigned int md_addr_t;
typedef unsigned int counter_t;
int myrand() { return 0; }
struct SatCounterTableEntry
{
enum SatCounter_State Predict_State;
md_addr_t tag;
};
static unsigned int Counter_Count;
static unsigned int sim_num_mispred_static;
static unsigned int sim_num_mispred_random;
static unsigned int sim_num_br;
static const unsigned int N = 0;
/* simulated registers */
static struct regs_t {} regs;
/* simulated memory */
static struct mem_t *mem = NULL;
/* track number of refs */
static counter_t sim_num_refs = 0;
/* maximum number of inst's to execute */
static unsigned int max_insts;
static struct SatCounterTableEntry* SatCounterTable;
void InitializeBPStructures()
{
SatCounterTable = (struct SatCounterTableEntry *)malloc(sizeof(struct SatCounterTableEntry) * Counter_Count);
}
void BranchPredict(md_addr_t PC, md_addr_t nextPC, enum Branch_Result result)
{
if (result == N)
sim_num_mispred_static++;
if (result != (myrand() % 2))
sim_num_mispred_random++;
sim_num_br++;
}
int main() {
}
You must have errors elsewhere in your code. Have I mentioned how incredibly hideous this design is? You should really be using objects for this.

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