Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pointer to a const structure, can members still be modified?

Tags:

c

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?

like image 746
BitFlip Avatar asked Aug 10 '18 07:08

BitFlip


People also ask

Can a const pointer be modified?

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.

Can you change what a const pointer points to?

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.

Can a struct member be const?

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 .

Can a pointer be declared 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.


1 Answers

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.
  • Actual implementation of struct s1 is in mylib.c thus all members are only visible to your library and not to user.
  • Getters and setters are implemented to set/read the value to these hidden members as only your library has access to members, making it completely hidden from user.
  • This forces him to use your functions.

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.

like image 143
tilz0R Avatar answered Sep 28 '22 05:09

tilz0R