In an attempt to encapsulate struct members (in a similar way as discussed in this question), I created the code below.
In the code below, I have a c-struct, which contains methods to access members of the struct which are hidden (by being cast into a struct otherwise the same but without the hidden properties)
#include <stdio.h>
typedef struct class {
int publicValue;
int (*getPV)();
void (*setPV)(int newPV);
} class;
typedef struct classSource {
int publicValue;
int apv;
int (*getPV)();
void (*setPV)(int newPV);
int PV;
} classSource;
class class_init() {
classSource cs;
cs.publicValue = 15;
cs.PV = 8;
int class_getPV() {
return cs.PV;
};
void class_setPV(int x) {
cs.PV = x;
};
cs.getPV = class_getPV;
cs.setPV = class_setPV;
class *c = (class*)(&cs);
return *c;
}
int main(int argc, const char * argv[]) {
class c = class_init();
c.setPV(3452);
printf("%d", c.publicValue);
printf("%d", c.getPV());
return 0;
}
When I run this, I get a segmentation fault error. However, I noticed that if I comment out certain lines of code, it (seems) to work okay:
#include <stdio.h>
typedef struct class {
int publicValue;
int (*getPV)();
void (*setPV)(int newPV);
} class;
typedef struct classSource {
int publicValue;
int apv;
int (*getPV)();
void (*setPV)(int newPV);
int PV;
} classSource;
class class_init() {
classSource cs;
cs.publicValue = 15;
cs.PV = 8;
int class_getPV() {
return cs.PV;
};
void class_setPV(int x) {
cs.PV = x;
};
cs.getPV = class_getPV;
cs.setPV = class_setPV;
class *c = (class*)(&cs);
return *c;
}
int main(int argc, const char * argv[]) {
class c = class_init();
c.setPV(3452);
//printf("%d", c.publicValue);
printf("%d", c.getPV());
return 0;
}
I presume that it might have something to do with using the initializer to add the getter and setter methods to the struct, as those might overwrite memory.
Is what I am doing undefined behavior? Is there a way to fix this?
EDIT: With the help of the answer below, I have re-written the code. In case anyone wants to see the implementation, below is the revised code
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int pub;
} class;
typedef struct {
class public;
int PV;
} classSource;
int class_getPV(class *c) {
return ((classSource*)c)->PV;
}
void class_setPV(class *c, int newPV) {
((classSource*)c)->PV = newPV;
}
class *class_init() {
classSource *cs = malloc(sizeof(*cs));
if((void*)cs == (void*)NULL) {
printf("Error: malloc failed to allocate memory");
exit(1);
}
cs->public.pub = 10;
cs->PV = 8;
return &(cs->public);
}
int main() {
class *c = class_init();
class_setPV(c,4524);
printf("%d\n",class_getPV(c));
printf("%d\n",c->pub);
free(c);
return 0;
}
There are at least three separate problems in your code.
You don't actually have a "struct otherwise the same but without the hidden properties". Your class and classSource structs have their getPV and setPV members in different places. Internally member access boils down to byte offsets from the beginning of the struct. To have a fighting chance of working, your code would need to have a common initial prefix of members between the two struct types (i.e. get rid of int apv; or move it to the end).
You're returning a struct by value, which automatically makes a copy. You've reimplemented the object slicing problem: Because the return value has type class, only the members of class will be copied. The extra members of classSource have been "sliced off".
You're using nested functions. This is not a standard feature of C; GCC implements it as an extension and says:
If you try to call the nested function through its address after the containing function exits, all hell breaks loose.
This is exactly what's happening in your code: You're calling c.setPV(3452); and c.getPV after class_init has returned.
If you want to fix these problems, you'd have to:
Fix your struct definitions. At minimum all members of class need to appear at the beginning of classSource in the same order. Even if you do that, I'm not sure you wouldn't still run into undefined behavior (e.g. you might be violating an aliasing rule).
I'm somewhat sure that embedding one struct in the other would be OK, however:
typedef struct classSource {
class public;
int PV;
} classSource;
Now you can return &cs->public from your initializer, and your methods can cast the class * pointer back to classSource *. (I think this is OK because all struct pointers have the same size/representation, and X.public as the first member is guaranteed to have the same memory address as X.)
Change your code to use pointers instead. Returning a pointer to a struct avoids the slicing problem, but now you have to take care of memory management (malloc the struct and take care to free it later).
Don't use nested functions. Instead pass a pointer to the object to each method:
class *c = class_init();
c->setPV(c, 3452);
int x = c->getPV(c);
This is somewhat tedious, but this is what e.g. C++ does under the hood, essentially. Except C++ doesn't put function pointers in the objects themselves; there's no reason to when you can either use normal functions:
setPV(c, 3452);
int x = getPV(c);
... or use a separate (global, constant, singleton) struct that just stores pointers to methods (and no data). Each object then only contains a pointer to this struct of methods (this is known as a vtable):
struct classInterface {
void (*setPV)(class *, int);
int (*getPV)(const class *);
};
static const classInterface classSourceVtable = {
class_setPV, // these are normal functions, defined elsewhere
class_getPV
};
Method calls would look like this:
c->vtable->setPV(c, 1234);
int x = c->vtable->getPV(c);
But this is mainly useful if you have several different struct types that share a common public interface (class) and you want to write code that works uniformly on all of them.
Related
I am new to C function pointer and structure. Here is what I want to achieve say there is a structure
typedef struct gfcrequest_t gfcrequest_t;
Later on this struct will be used to point to a function and the function will be called
gfcrequest_t *gfc_create();
gfr = gfc_create();
gfc_set_server(&gfr, server);
gfc_set_port(&gfr, port);
So are the following codes correct to initiate and later on I could add elements like server name and port number?
gfcrequest_t *gfc_create() {
struct out {
struct hostent *server;
int portno;
};
return out;
}
void gfc_set_port(gfcrequest_t **gfr, unsigned short port) {
gfr.portno = port;
}
void gfc_set_server(gfcrequest_t **gfr, const char *server) {
gfr.server = gethostbyname(server);
}
thats not how you do pointers to function.
to declare a pointer to function you do this:
if your function is:
int ft_somefink (int a, int b);
the pointer should be:
struct s_structure;
typedef struct s_structure t_structure;
struct s_structure
{
int (*funct)(int, int);
};
the typedef is there to simplify syntax.
its just an alias to avoid having to type "struct" everytime you use the structure.
you initialize it like so:
int main ()
{
t_structure name;
name.funct = &ft_somefink;
}
And call it like so:
int main()
{
t_structure name;
int a;
int b;
a = 1;
b = 2;
name.funct = &ft_somefink;
...
name.funct(a, b);
}
or like so if you pass the structure as pointer, it should look like this:
the main:
int main ()
{
t_structure *name;
...
function_somthing_useful(&name);
}
and the function:
void function_something_useful(t_structure **name)
{
if (!(*name = malloc(sizeof(t_structure))))
{
fprintf(stderr, "malloc error, not enough memory or swap nvm\n")
return ;
}
name->funct = &ft_somefink;
}
And, obviously, you call it then by:
name->funct(a, b);
note that you can malloc in main, doesnt matter. the idea to pass just the pointer is to avoid having to copy the whole structure everytime you pass it to a function.
the difference between . and -> operator is a dereferencing, but that would be another subject.
also i think it is better to pass the function as a pointer, instead of the whole thing because that might imply copying all of the functions instructions. not 100% sure of that tho... or rather depends on the system.
on linux reads are suposed to be "atomic", which, in my experience includes what happens on the stack. couldnt speak about other systems tho...
definitely could use someone to fill in the blanks here...
I want to create a constructor using C.
What is the cleanest way to achieve this?
My attempt:
#include <stdio.h>
struct line {
void (*add_line_ptr)(struct line*, int x, int y);
int x;
int y;
};
void add_line(struct line* lptr, int x, int y)
{
lptr->x = x;
lptr->y = y;
}
int main()
{
struct line line1 = {add_line, 0, 0};
line1.add_line_ptr(&line1, 10, 20);
printf("%d %d\n", line1.x, line1.y);
}
I think that using line1.add_line(&line1, is a bit redundant - since it's quite obvious that I want to do the operation on line1.
Is there a way to implement this without passing a pointer to the "object"(struct)? or some other way I didn't think of?
Using function pointers just for the sake of emulating C++-like syntax is just messy with no obvious benefits. You won't have RAII in C no matter what you do, so you need to call constructors/destructors explicitly. If you do so by typing obj.foo() or obj = foo() has absolutely nothing to do with OO, it's mere coding style.
The main problem here though, is that your code does not have proper OO design, since the struct is completely open and not using private encapsulation. For the same reason as class line { public: int x; int y; }; is not proper OO either - you don't get OO just because you smash some related variables into an aggregate type, regardless of language.
"Cleanest"/"prettiest" would mean full private encapsulation. In C, that can be achieved with opaque types. I prefer to implement them without hiding pointers behind typedef, so:
line.h
#include <stdio.h>
#include <stdlib.h>
typedef struct line line; // forward declaration of incomplete type
line* line_construct (int x, int y);
line.c
#include "line.h"
struct line { // actual definition of the struct, local to line.c
int x; // private variable
int y; // private variable
};
line* line_construct (int x, int y)
{
line* obj = malloc (sizeof *obj);
if(obj == NULL) { /* error handling here */ }
obj->x = x;
obj->y = y;
return obj;
}
caller.c
#include "line.h"
int main(void)
{
line* x = line_construct(10, 20);
}
Here line is 100% encapsulated and the contents of the struct cannot be accessed by the caller. Since I don't hide pointers behind typedef, the caller must always use line* pointers and can never declare an instance of the object directly.
If the constructor is only meant to zero-out the struct members, then it doesn't need to get passed any parameters but can do so internally.
And obviously you need to implement a corresponding destructor with free as well.
line* line_destruct(line* obj) { free(obj); return NULL; } or so.
I wouldn't put the initializer into your structure to begin with. Other functions, sure, but not the first one. Something like this:
#include <stdio.h>
struct line {
int x;
int y;
};
void add_line(struct line *lptr, int x, int y)
{
lptr->x = x;
lptr->y = y;
}
int main()
{
struct line line1 = {0, 0};
add_line(&line1, 10, 20);
printf("%d %d\n", line1.x, line1.y);
}
The reason is that you have to assign the initializer anyway after you allocate your structure, either implicitly or explicitly. In OOP languages you normally name the class you want once, and both the allocator and initializer will run. In C you have to run them separately. Whether you allocate an object on the stack or on the heap, you will have to explicitly name the function you want to call at least once anyway.
So I have two different structs in which all the properties that I will be accessing will be the same. and I also have a function, who's argument, i want to be able to accept either of the two. Example:
typedef struct{
int whatnot = 14;
int thing[11];
} TH_CONFIG;
typedef struct{
int whatnot = 3;
int thing[5];
} TH_CONFIG_2;
*_CONFIG var;
void fun(*_CONFIG input)
{
input.whatnot = 5;
}
int main(){
fun(var);
}
I may have an inkling that I should use void as the type from that I could typecast or something?, but my searching has only yielded things about function pointers, templates, and C#.
EDIT: *_CONFIG is not meant to be syntactically correct, its signifying that I don't know what to do there, but its supposed to be the _CONFIG type
Possible solutions.
Just use an array of length 11 for both of them. Did you really run out of those last 6 bytes on your OS?
Make it a dynamic array.
Just write in assembly, you clearly don't care about C's higher-level-ness.
Use a language like C++ that supports templates or polymorphism.
Just pass in the arguments of the struct you care about.
void fun(int* whatnot) {
*whatnot = 5;
}
int main() {
fun(&myStruct.whatnot);
return 0;
}
Factor into a quasi-OO design.
struct {
int whatnot;
} typedef Common;
struct TH_CONFIG_1 {
Common common;
int thing[11];
};
struct TH_CONFIG_2 {
Common common;
int thing[5];
}
But if you insist...
void fun(void* input) {
( (int)(*input) ) = 5;
}
or...
void fun(void* input) {
( (TH_CONFIG*) input)->whatnot = 5; // may have been a TH_CONFIG_2, but who cares?
}
Note: this would not pass code review at any C shop.
You can use any pointer type and cast it.
If all the properties you're accessing are the same, I'm guessing one's an extension of the other (since the properties need to have the same offset from the beginning of the struct). In that case you may want to use this pattern:
struct base {
int foo;
char **strings;
};
struct extended {
struct base super;
double other_stuff;
};
Since super is at the start of struct extended, you can cast a struct extended * to struct base * without problems. Of course, you could do that by repeating the same fields in the beginning of struct extended instead, but then you're repeating yourself.
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;
}
I have some code with multiple functions very similar to each other to look up an item in a list based on the contents of one field in a structure. The only difference between the functions is the type of the structure that the look up is occurring in. If I could pass in the type, I could remove all the code duplication.
I also noticed that there is some mutex locking happening in these functions as well, so I think I might leave them alone...
If you ensure that the field is placed in the same place in each such structure, you can simply cast a pointer to get at the field. This technique is used in lots of low level system libraries e.g. BSD sockets.
struct person {
int index;
};
struct clown {
int index;
char *hat;
};
/* we're not going to define a firetruck here */
struct firetruck;
struct fireman {
int index;
struct firetruck *truck;
};
int getindexof(struct person *who)
{
return who->index;
}
int main(int argc, char *argv[])
{
struct fireman sam;
/* somehow sam gets initialised */
sam.index = 5;
int index = getindexof((struct person *) &sam);
printf("Sam's index is %d\n", index);
return 0;
}
You lose type safety by doing this, but it's a valuable technique.
[ I have now actually tested the above code and fixed the various minor errors. It's much easier when you have a compiler. ]
Since structures are nothing more than predefined blocks of memory, you can do this. You could pass a void * to the structure, and an integer or something to define the type.
From there, the safest thing to do would be to recast the void * into a pointer of the appropriate type before accessing the data.
You'll need to be very, very careful, as you lose type-safety when you cast to a void * and you can likely end up with a difficult to debug runtime error when doing something like this.
I think you should look at the C standard functions qsort() and bsearch() for inspiration. These are general purpose code to sort arrays and to search for data in a pre-sorted array. They work on any type of data structure - but you pass them a pointer to a helper function that does the comparisons. The helper function knows the details of the structure, and therefore does the comparison correctly.
In fact, since you are wanting to do searches, it may be that all you need is bsearch(), though if you are building the data structures on the fly, you may decide you need a different structure than a sorted list. (You can use sorted lists -- it just tends to slow things down compared with, say, a heap. However, you'd need a general heap_search() function, and a heap_insert() function, to do the job properly, and such functions are not standardized in C. Searching the web shows such functions exist - not by that name; just do not try "c heap search" since it is assumed you meant "cheap search" and you get tons of junk!)
If the ID field you test is part of a common initial sequence of fields shared by all the structs, then using a union guarantees that the access will work:
#include <stdio.h>
typedef struct
{
int id;
int junk1;
} Foo;
typedef struct
{
int id;
long junk2;
} Bar;
typedef union
{
struct
{
int id;
} common;
Foo foo;
Bar bar;
} U;
int matches(const U *candidate, int wanted)
{
return candidate->common.id == wanted;
}
int main(void)
{
Foo f = { 23, 0 };
Bar b = { 42, 0 };
U fu;
U bu;
fu.foo = f;
bu.bar = b;
puts(matches(&fu, 23) ? "true" : "false");
puts(matches(&bu, 42) ? "true" : "false");
return 0;
}
If you're unlucky, and the field appears at different offsets in the various structs, you can add an offset parameter to your function. Then, offsetof and a wrapper macro simulate what the OP asked for - passing the type of struct at the call site:
#include <stddef.h>
#include <stdio.h>
typedef struct
{
int id;
int junk1;
} Foo;
typedef struct
{
int junk2;
int id;
} Bar;
int matches(const void* candidate, size_t idOffset, int wanted)
{
return *(int*)((const unsigned char*)candidate + idOffset) == wanted;
}
#define MATCHES(type, candidate, wanted) matches(candidate, offsetof(type, id), wanted)
int main(void)
{
Foo f = { 23, 0 };
Bar b = { 0, 42 };
puts(MATCHES(Foo, &f, 23) ? "true" : "false");
puts(MATCHES(Bar, &b, 42) ? "true" : "false");
return 0;
}
One way to do this is to have a type field as the first byte of the structure. Your receiving function looks at this byte and then casts the pointer to the correct type based on what it discovers. Another approach is to pass the type information as a separate parameter to each function that needs it.
You can do this with a parameterized macro but most coding policies will frown on that.
#include
#define getfield(s, name) ((s).name)
typedef struct{
int x;
}Bob;
typedef struct{
int y;
}Fred;
int main(int argc, char**argv){
Bob b;
b.x=6;
Fred f;
f.y=7;
printf("%d, %d\n", getfield(b, x), getfield(f, y));
}
Short answer: no. You can, however, create your own method for doing so, i.e. providing a specification for how to create such a struct. However, it's generally not necessary and is not worth the effort; just pass by reference. (callFuncWithInputThenOutput(input, &struct.output);)
I'm a little rusty on c, but try using a void* pointer as the variable type in the function parameter. Then pass the address of the structure to the function, and then use it he way that you would.
void foo(void* obj);
void main()
{
struct bla obj;
...
foo(&obj);
...
}
void foo(void* obj)
{
printf(obj -> x, "%s")
}