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 );
typedef struct item {
char *text;
int count;
struct item *next;
};
So I have this struct with nodes defined as above, but Im getting the error below and Im not able to figure out whats wrong.
warning: useless storage class specifier in empty declaration
};
I'm not sure, but try like that :
typedef struct item {
char *text;
int count;
struct item *next;
}item;
typedef is used to create a shorthand notation for an existing type in C. It is similar to #define but unlike it, typedef is interpreted by the compiler and offers more advanced capabilities than the preprocessor.
With its simplest form, typedef is given as
typedef existing_type new_type;
for instance,
typedef unsigned long UnsignedLong;
For example, if you trace the definition of size_t back to its root, you will see that
/* sys/x86/include/_types.h in FreeBSD */
/* this is machine dependent */
#ifdef __LP64__
typedef unsigned long __uint64_t;
#else
__extension__
typedef unsigned long long __uint64_t;
#endif
...
...
typedef __uint64_t __size_t;
and then
/* stddef.h */
typedef __size_t size_t;
which actually means, size_t is an alias for unsigned long long,depending on the 64-bit modal (LP64, ILP64, LLP64) your machines has.
For your question, you attempt to define a new type but do not name it. Don't let the struct item {..} definition confuse you, it is just a type you are declaring. If you replace the whole struct item {...} with a basic type, say with an int, and rewrite your typedef, you would end up something like this
typedef int; /* new type name is missing */
the correct form should be
typedef struct item {...} Item;
See the examples below for different structure definitions
#include <stdio.h>
/* a new type, namely Item, is defined here */
typedef struct item_t {
char *text;
int count;
struct item_t *next; /* you canot use Item here! */
} Item;
/* a structure definition below */
struct item {
char *text;
int count;
struct item *next;
};
/* an anonymous struct
* However, you cannot self-refence here
*/
struct {
int i;
char c;
} anon;
int main(void) {
/* a pointer to an instance of struct item */
struct item *pi;
/* Shorthand for struct item_t *iI */
Item *iI;
/* anonymoous structure */
anon.i = 9;
anon.c = 'x';
return 0;
}
The typedef is useless because you didn't give it a name. You cannot use the typedef in any way. That's why you get a warning, because the typedef is useless.
The struct is actually still usable without the warning if you remove the typedef keyword like this:
struct item {
char *text;
int count;
struct item *next;
};
You just need to include the 'struct' keyword in the variable declaration. i.e.
struct item head;
as other have pointed out if you include the name at the end of the struct definition then you can use it as the typedef and you get rid of the warning even without the struct keyword but this makes the first instance of 'item' superfluous i.e.
typedef struct {
char *text;
int count;
struct item *next;
} item;
item head;
will also get rid of the warning.
This is an oldie, but stumbled here because I had the same linker error.
I made the foolish mistake of naming a file with an extension .c, and should have been .cpp - created the SAME error - so watch out!
Renamed the file to have a .cpp extension, and the problem magically went away.
Took a while to figure that out, so happy to share my experience.
I have a stack that contains two types of struct. Struct Stud and Struct Prof.
When I want to push something I created two Push functions for both structs. Although I would like it to be with one function but its ok I can bear with it.
Now to Pop. If I want to Pop a student from the Stack, do I have to make a Pop function specifically for Students only? The same with Professors?
How can I store the item if I don't know what type is it? What type must the element be, to store the item there?
Here are the structs:
struct MyStack
{
int head;
void **stack;
int size;
};
typedef struct MyStack STACK;
struct stud
{
char flag;
char fname[50];
int semester;
};
struct prof
{
char flag;
char fname[50];
char course[30];
};
Now to create the Pop function. What do type of item do I pass in the function?
int Pop(STACK *stack,int *head,??? *elem)
{
if(stack->head<=-1)
return 0;
*elem=stack->stack[*head];
*head--;
return 1;
}
You have to encode the type information when you push, simplest is probably to type tag:
#define STUD 0
#define PROF 1
struct stack_entry {
int type;
void *item;
};
struct MyStack
{
int head;
struct stack_entry *stack;
int size;
};
Then change your push functions to attach the right tag when you push. Then, in pop, simplest again is probably to just return a stack_entry struct, and let the calling function figure it out. At that point you might want a snazzier name than "stack_entry" though. Also, it would be slightly preferable to use a union:
struct stack_entry {
int type;
union {
struct stud *stud;
struct prof *prof;
} item;
}
Because then the compiler can help you out a bit, but of course you still have to be more or less as careful as you would be with a void *.
Edit: initialization...
You don't have to mark then end of the buffer with anything, since you have a size variable in the struct. But if you wanted to do that I would have that be its own type
#define END_OF_BUFFER 1
#define STUD 2
#define PROF 3
And then for init you could do:
stack->size = size;
stack->stack = calloc(sizeof(*stack->stack), size + 1);
stack->stack[size].type = END_OF_BUFFER;
stack->head=-1;
Though I tend to use "head" to refer to a pointer that points to the next place to write to, but I'm not sure how standard that is. But the buffer is an array of strack_entries, not void *'s.
(btw I'm not allowed to malloc in this, I'm writing in c for c99)
I'm trying to create a wrapper struct in c for arrays to keep things tidy so I don't need to keep passing the array pointer and the length around, and can just use a struct:
#define MAX_LEN 64
typedef struct {
uint8_t data[MAX_LEN];
size_t len;
} byteArray_t;
Which is fine if MAX_LEN is known, but is there a way to make the length variable although known at compile time, so that for example I could have something like:
typedef struct {
byteArray_t tag;
byteArray_t length;
byteArray_t value;
} tlv_t;
In which the array corresponding to tag would have size MAX_TAG_LEN and so on for the others - so I'd need to tell the compiler somehow that that was the case...
Anyone got any ideas? Thanks!
Edit
Alright, sorry for the confusion. Here's what I'm trying to do.
I basically have the following structures at present:
// tag object
typedef struct {
uint8_t data[MAX_TAG_LENGTH_IN_BYTES];
uint32_t len;
} tlvTag_t;
// length object
typedef struct {
uint8_t data[MAX_LENGTH_OF_LENGTH_IN_BYTES];
uint32_t len;
} tlvLength_t;
typedef struct tlv tlv_t;
// value object definition
typedef struct {
// can consist of a byte array, or a list of sub TLVs
union {
uint8_t data[MAX_VALUE_LENGTH_IN_BYTES];
// data can be parsed into subTLVs
tlv_t* subTLVs;
};
// need to store the number of subTLVs
uint32_t numberOfSubTLVs;
// len is the total length of the data represented:
// the total length of the subTLVs placed end to end
// or the length of the data array.
uint32_t len;
} tlvValue_t;
// tlv object definition
struct tlv {
tlvTag_t tag;
tlvLength_t len;
tlvValue_t value;
// total length of entire tlv block (not value length)
// (if there are sub TLVs, place them end to end)
uint32_t totalLen;
};
I thought the design would be better if I could wrap the arrays in another struct to avoid all the code duplication and be able to pass fewer arguments around, but I can't because I don't know how to tell the compiler to create different sized byte arrays - maybe it's possible using macros? Hope that makes sense.
It seems you are trying to somehow declare a struct whose contents depend on a parameter. In c++ this could be implemented by a template:
template <size_t MAX_LEN>
struct byteArray_t
{
uint8_t data[MAX_LEN];
size_t len;
};
...
byteArray_t<MAX_TAG_LENGTH_IN_BYTES> tag;
byteArray_t<MAX_LENGTH_OF_LENGTH_IN_BYTES> len;
...
This is as straightforward as it can get.
To accomplish the same in C, you can use macros:
#define DECLARE_BYTE_ARRAY_T(your_type_name, MAX_LEN) \
typedef struct { \
uint8_t data[MAX_LEN]; \
size_t len; \
} your_type_name
DECLARE_BYTE_ARRAY_T(tlvTag_t, MAX_TAG_LENGTH_IN_BYTES);
DECLARE_BYTE_ARRAY_T(tlvLenght_t, MAX_LENGTH_OF_LENGTH_IN_BYTES);
...
tlvTag_t tag;
tlvLength_t len;
Or (the same) without declaring types (good if you don't need names for your structs):
#define BYTE_ARRAY_T(MAX_LEN) \
struct { \
uint8_t data[MAX_LEN]; \
size_t len; \
}
BYTE_ARRAY_T(MAX_TAG_LENGTH_IN_BYTES) tag;
BYTE_ARRAY_T(MAX_LENGTH_OF_LENGTH_IN_BYTES) len;
This may be marginally better than the code you already have. However, in my opinion, this is not worth the effort, because any non-trivial macro decreases readability of code.
If you make a struct like this and then pass it by value to a function, then the whole array gets passed by value. You do not want that.
Actually you don't need an array inside the struct, just declare it elsewhere.
typedef struct {
uint8_t* data;
size_t len;
} byteArray_t;
int main()
{
uint8_t some_array[X];
...
byteArray_t wrapper = {some_array, X};
some_function (&wrapper);
}
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;
}