C — Accessing a non-const through const declaration

前端 未结 5 1077
轮回少年
轮回少年 2020-11-30 13:15

Is accessing a non-const object through a const declaration allowed by the C standard? E.g. is the following code guaranteed to compile and output

相关标签:
5条回答
  • 2020-11-30 13:38

    In the B translation unit, const would only prohibit modifying the a variable within the B translation unit itself.

    Modifications of that value from outside (other translation units) will reflect on the value you see in B.

    This is more of a linker issue than a language issue. The linker is free to frown upon the differing qualifications of the a symbol (if there is such information in the object files) when merging the compiled translation units.

    Note, however, that if it's the other way around (const int a = 23 in A and extern int a in B), you would likely encounter a memory access violation in case of attempting to modify a from B, since a could be placed in a read-only area of the process, usually mapped directly from the .rodata section of the executable.

    0 讨论(0)
  • 2020-11-30 13:43

    TU A contains the (only) definition of a. So a really is a non-const object, and it can be accessed as such from a function in A with no problems.

    I'm pretty sure that TU B invokes undefined behavior, since its declaration of a doesn't agree with the definition. Best quote I've found so far to support that this is UB is 6.7.5/2:

    Each declarator declares one identifier, and asserts that when an operand of the same form as the declarator appears in an expression, it designates a function or object with the scope, storage duration, and type indicated by the declaration specifiers.

    [Edit: the questioner has since found the proper reference in the standard, see the question.]

    Here, the declaration in B asserts that a has type volatile const int. In fact the object does not have (qualified) type volatile const int, it has (qualified) type int. Violation of semantics is UB.

    In practice what will happen is that TU A will be compiled as if a is non-const. TU B will be compiled as if a were a volatile const int, which means it won't cache the value of a at all. Thus, I'd expect it to work provided the linker doesn't notice and object to the mismatched types, because I don't immediately see how TU B could possibly emit code that goes wrong. However, my lack of imagination is not the same as guaranteed behavior.

    AFAIK, there's nothing in the standard to say that volatile objects at file scope can't be stored in a completely different memory bank from other objects, that provides different instructions to read them. The implementation would still have to be capable of reading a normal object through, say, a volatile pointer, so suppose for example that the "normal" load instruction works on "special" objects, and it uses that when reading through a pointer to a volatile-qualified type. But if (as an optimization) the implementation emitted the special instruction for special objects, and the special instruction didn't work on normal objects, then boom. And I think that's the programmer's fault, although I confess I only invented this implementation 2 minutes ago so I can't be entirely confident that it conforms.

    0 讨论(0)
  • 2020-11-30 13:47

    FWIW: In H&S5 is written (Section 4.4.3 Type Qualifiers, page 89): "When used in a context that requires a value rather than a designator, the qualifiers are eliminated from the type." So the const only has an effect when someone tries to write something into the variable. In this case, the printf's use a as an rvalue, and the added volatile (unnecessary IMHO) makes the program read the variable anew, so I would say, the program is required to produce the output the OP saw initially, on all platforms/compilers. I'll look at the Standard, and add it if/when I find anything new.

    EDIT: I couldn't find any definite solution to this question in the Standard (I used the latest draft for C1X), since all references to linker behavior concentrate on names being identical. Type qualifiers on external declarations do not seem to be covered. Maybe we should forward this question to the C Standard Committee.

    0 讨论(0)
  • 2020-11-30 13:50

    Declaring it as const means that the instance is defined as const. You cannot access it from a not-const. Most compilers will not allow it, and the standard says it's not allowed either.

    0 讨论(0)
  • 2020-11-30 13:53

    The declaration that has the initialization is the definition, so your object is indeed not a const qualified object and foo has all the rights to modify it.

    In B your are providing access to that object that has the additional const qualification. Since the types (the const qualified version and the non-qualified version) have the same object representation, read access through that identifier is valid.

    Your second printf, though, has a problem. Since you didn't qualify your B version of a as volatile you are not guaranteed to see the modification of a. The compiler is allowed to optimize and to reuse the previous value that he might have kept in a register.

    0 讨论(0)
提交回复
热议问题