I have a structure which I want to pass to some external c code via some callback function that they register with my program. However, I want to pass that structure as read-only. My concern is that they can still modify the structures which I have pointer to inside the original structure that I pass. Explained with small example below:
struct s1 {
int a;
int b;
};
struct s2 {
int x;
struct s1 *y;
};
void f(const struct s2 *o)
{
//o->x=10; //error
o->y->a=20; //no error
o->y->b=30; //no error
}
int main()
{
struct s1 o1 = {10, 20};
struct s2 o2 = {30, &o1};
f(&o2);
}
So, How do I improve my code design so that they cannot modify anything w.r.t the structure I pass?
Because the data type being pointed to is const, the value being pointed to can't be changed. We can also make a pointer itself constant. A const pointer is a pointer whose address can not be changed after initialization.
A pointer to constant is a pointer through which the value of the variable that the pointer points cannot be changed. The address of these pointers can be changed, but the value of the variable that the pointer points cannot be changed.
You can const individual members of a struct. Declaring an entire instance of a struct with a const qualifier is the same as creating a special-purpose copy of the struct with all members specified as const .
We can create a pointer to a constant in C, which means that the pointer would point to a constant variable (created using const). We can also create a constant pointer to a constant in C, which means that neither the value of the pointer nor the value of the variable pointed to by the pointer would change.
To properly handle this situation, you can only use forward declaration to hide members together with getter and setter functions.
Focus on code below and check:
struct s1
only has forward declaration so you can make a pointer to it in struct s2
. struct s1
is in mylib.c
thus all members are only visible to your library and not to user.mylib.h:
#ifndef __MYLIB_H
#define __MYLIB_H
//Create forward declaration only
//Implementation is in .c file
struct s1;
//Create user structure
struct s2 {
int x;
struct s1* y;
};
int get_a_from_s1(struct s2* s);
void set_a_to_s1(struct s2* s, int a);
#endif /* __MYLIB_H */
mylib.c:
#include "mylib.h"
//Now implement structure
struct s1 {
int a, b;
};
//Make getter
int
get_a_from_s1(struct s2* s) {
return s->y->a;
}
//Make setter
void
set_a_to_s1(struct s2* s, int a) {
s->y->a = a;
}
main.c:
#include <stdio.h>
#include "mylib.h"
int main(void) {
struct s2 s;
int a;
....
s.y->a = 5; //error
//Set s1.a value from s2 structure
set_a_to_s1(&s, 10); //OK
//To view members of s1 inside s2, create member functions
a = get_a_from_s1(&s); //OK
printf("a: %d\r\n", a);
return 0;
}
Of course, please make sure that ->y
is not NULL
or you have undefined behavior.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With