cmemoryconstants

What is the const qualifier attached to in C: the memory area or the pointer?


I wondered, if the const qualifier in C is the attribute of the pointer or the memory area?

If I do something like:

struct S { int data; }
struct CS { const int data; }

char *p = malloc(100);

struct S *s = p+10;
struct CS *cs = p+10;

Can I access the same memory area by CS for reading and S for writing, without these two ever knowing of each other?

Or does the const mark that exact memory area to be const?

Q&A: No, I can't just "try it out", because I don't know when and how this difference can come in play. All the experiences I had so far point to the const being strictly a variable attribute. Is that so, or have I just missed that one example that proves me wrong?


Solution

  • const has two effects. One is when an object is defined with const, that memory is “permanently tainted”: Any attempt to modify the object’s memory is not defined by the C standard. The C implementation may make that memory read-only. That effect is not relevant to your example.

    The second is that const qualifies a type and requires diagnostic messages when the type is “misused”. For example if a const int * is assigned to an int * (with no cast), the compiler must issue a diagnostic. Or if any value is assigned to a const int, the compiler must issue a diagnostic. This also is not an issue in your example.

    There is a third effect, although it is a property of all aspects of types, not just the const qualifier: It makes one type different from another. And then the types are subject to the aliasing rule in C 2024 6.5. And that controls the answer to your question:

    Can I access the same memory area by CS for reading and S for writing, without these two ever knowing of each other?

    The C standard is a bit hazy on this. Let’s consider two cases. The first is you write to s with *s = (struct S) { 4 }; and read from cs with struct CS foo = *cs;. The write is defined; without going into detail, the rules of effective type and aliasing say you may write to dynamically allocated memory with any type. Let’s consider the read.

    Once dynamically allocated memory is written with a non-character type, that type becomes its effective type for subsequent reads. So, *s = (struct S) { 4 }; gives the memory an effective type of struct S.

    The aliasing rules say that accessing this memory using struct CS is not defined, because they say an object shall be accessed only with one of these types:

    Therefore, struct CS foo = *cs; is not defined by the C standard.

    The second case is you write to s with s->data = 4; and you read from cs with int foo = cs->data;. In this case, the effective type of the memory is int,1 and we read from it with const int. This is allowed by the aliasing rules because one of the allowed types is:

    Footnote

    1 This is hazy because the C standard does not explicitly address the type when a structure is written to dynamically allocated memory by individually writing all of its members. Does that combine to form a structure object in that memory? If memory is written as a structure, giving it an effective type of that structure, can we individually access its members? There is probably a language-lawyer question on this elsewhere on Stack Overflow.