Home > Blockchain >  What is the use of the const keyword when assigning structure values?
What is the use of the const keyword when assigning structure values?

Time:10-13

What is the use of const keyword in this program?

#include <stdio.h>

struct x{
    int a;
    int b;
};

int main()
{
    struct x xx;
    xx = (const struct x) {0};
    xx.a = 10;
    printf("%d, %d", xx.a, xx.b);
}

There is no difference in output when I run without const keyword. What is its significance here?

CodePudding user response:

C 2018 6.3.2.1 2 says qualifiers such const are removed when any object is used for its value in an expression:

Except when it is the operand of the sizeof operator, the unary & operator, the operator, the -- operator, or the left operand of the . operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue); this is called lvalue conversion. If the lvalue has qualified type, the value has the unqualified version of the type of the lvalue; additionally, if the lvalue has atomic type, the value has the non-atomic version of the type of the lvalue; otherwise, the value has the type of the lvalue.

Thus, in xx = (const struct x) {0};, (const struct x) {0}; is a compound literal that creates a const struct x object. However, in taking the value of this object, const is removed, and the result is a struct x value. (The “value” of a structure is the aggregate of the values of all its members.)

Thus, in this use, the const ultimately has no effect. However, the compound literal does create a const object. The effect of this could be seen in other uses. For example, with const struct x *p = & (const struct x) {0};, we take the address of the compound structure. Then if we attempt to remove const and modify the structure, as with ((struct x *) p)->a = 3;, the behavior is not defined by the C standard. The compiler could have placed the structure in read-only memory, and attempting to modify it could generate a trap. Or, during optimization, the compiler could have used the fact that the structure is const to ignore any possibility it could change. For example, in:

const struct *p = & (const struct x) {0};
((struct x *) p)->a = 3;
printf("%d\n", p->a);

the program might print “0” because in the p->a in the printf, the compiler uses the fact that p->a is defined to be a const zero.

CodePudding user response:

But what is it's significance here?

None.

When you assign to xx like xx = something; you need that something to have the basic type struct x. That happens due to the cast. So if you do

(struct x) {0};

an anonymous object of type struct x will be created and it can be assigned to xx like:

xx = (struct x) {0};

Now adding a const qualifier in the cast means that the anonymous object is a constant. However, it doesn't really matter that it's constant as you don't write to it anyway. The only operation performed on the anonymous object is the read operation performed during the assignment to xx. For an assignment it makes no difference whether the source object (RHS object) is a constant or not.

So: No, for your code const has no significance.

Can we construct code where it matters?

Yes, consider this (obfuscated useless) code:

int y;
y =   (struct x) {0, 42}.b;
printf("%d\n", y);

It will create an anonymous object with values .a=0 and .b=42 and then increment and return .b. In other words, it will print 43.

If you add const to the cast, you'll get a compiler error like:

main.cpp:26:9: error: increment of member 'b' in read-only object
   26 |     y =   (const struct x) {0, 42}.b;
      |         ^~

So here the const keyword did matter.

CodePudding user response:

This will zero-initialize a temporary struct x:

xx = (const struct x) {0};

and that temporary will then be used to copy assign xx. That's what it will do no matter if the temporary object is const or not.


An example with a popular compiler (gcc) shows that it'll simply zero out the two members in xx, in both the const and non-const case without actually creating a temporary object. The compiled program acts as-if it did though:

xor     edx, edx
xor     esi, esi
  • Related