Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can GCC warn me about modifying the fields of a const struct in C99?

I stumbled upon a small issue while trying to make const-correct code.

I would have liked to write a function that takes a pointer to a const struct, to tell to the compiler "please tell me if I am modifying the struct, because I really do not want to".

It suddenly came to my mind that the compiler will allow me to do this:

struct A {     char *ptrChar; };  void f(const struct A *ptrA) {     ptrA->ptrChar[0] = 'A'; // NOT DESIRED!! } 

Which is understandable, because what actually is const is the pointer itself, but not the type it points to. I would like for the compiler to tell me that I'm doing something I do not want to do, though, if that is even possible.

I used gcc as my compiler. Although I know that the code above should be legal, I still checked if it would issue a warning anyways, but nothing came. My command line was:

gcc -std=c99 -Wall -Wextra -pedantic test.c 

Is it possible to get around this issue?

like image 283
Samuel Navarro Lou Avatar asked Feb 26 '16 08:02

Samuel Navarro Lou


People also ask

Can a struct have const member?

No, a struct is a class where members and bases are public by default. Structs can still have private members.

Can const be applied on structure objects?

'const' as the word constant itself indicates means unmodifiable. This can be applied to variable of any data type. struct being a user defined data type, it applies to the the variables of any struct as well. Once initialized, the value of the const variables cannot be modified.


1 Answers

A way to design your way around this, if needed, is to use two different types for the same object: one read/write type and one read-only type.

typedef struct {   char *ptrChar; } A_rw;  typedef struct {   const char* ptrChar; } A_ro;   typedef union {   A_rw rw;   A_ro ro;   } A; 

If a function needs to modify the object, it takes the read-write type as parameter, otherwise it takes the read-only type.

void modify (A_rw* a) {   a->ptrChar[0] = 'A'; }  void print (const A_ro* a) {   puts(a->ptrChar); } 

To pretty up the caller interface and make it consistent, you can use wrapper functions as the public interface to your ADT:

inline void A_modify (A* a) {   modify(&a->rw); }  inline void A_print (const A* a) {   print(&a->ro); } 

With this method, A can now be implemented as opaque type, to hide the implementation for the caller.

like image 158
Lundin Avatar answered Sep 28 '22 09:09

Lundin