Const does not mean read only

Daniel Andersson
2024-08-05

Const is just a contract for the programmer and compiler, there is no safeguard for the value changing. The compiler will warn you about discarding qualifiers, but those can be easy to miss if there are a lot of warnings in a project already. Local const variables typically end up on the stack, which can be accidentally overwritten.

One way to have the variable read only is to mark it as static const, then local or global variables likely end up in the read only section in the compiled binary or shared library. What then happens when the read only variable is written to is that the program crashes, probably segfaulting. Normally I’d prefer not to crash applications on errors, that is bad user experience, but hopefully writing to a read only variable will be caught during development.

The only case I would use pure const for is probably an API to a library, that is to be used by others. That being said, as a contractor I’ll follow whatever the coding standard is.

What I typically do is make a macro

#define read_only static const
#include <stdio.h>
#include <stdlib.h>

#define read_only static const
read_only int global_ro = 42;

void change_read_only(int *src, int val)
{
  *src = val;
}

int main(int argc, char **argv)
{
  const int foo = argc == 2 ? atoi(argv[1]) : 2;
  printf("const int foo %d\n", foo);
  change_read_only(&foo, 42);
  printf("const int foo %d\n", foo);
  //change_read_only(&global_ro, foo); // Segfaults
}

It also seems possible to make your own read only sections in the compiled/linked output. I have not used it myself but on windows you can apparently use a pragma to create a new read only section in the binary/dll and use declspec to put the variable in the section

#pragma section("myrodata", read)
#define read_only __declspec(allocate("myrodata"))

With POSIX it may be a little more involved, first you mark your variables with __attribute((section("myrodata"))) and then after the binary is compiled and linked, you use objcopy --set-section-flags myrodata=alloc,load,readonly binaryname, in order to mark that section read only.