分配结构值时 const 关键字的用途是什么?

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

const关键字在这个程序中有什么用?

#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);
}

当我 运行 没有 const 关键字时,输出没有区别。它在这里有什么意义?

But what is it's significance here?

None.

当您像 xx = something; 一样分配给 xx 时,您需要 something 具有基本类型 struct x。发生这种情况是由于演员阵容。所以如果你这样做

(struct x) {0};

将创建一个类型为 struct x 的匿名对象,并且可以将其分配给 xx,例如:

xx = (struct x) {0};

现在在强制转换中添加 const 限定符意味着匿名对象是常量。但是,它保持不变并不重要,因为无论如何您都不会写入它。对匿名对象执行的唯一操作是在对 xx 赋值期间执行的读取操作。对于赋值,源对象(RHS 对象)是否为常量没有区别。

所以:不,对于您的代码 const 没有任何意义。

我们可以在重要的地方构建代码吗?

是的,考虑这个(混淆无用的)代码:

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

它将创建一个匿名对象,其值为 .a=0.b=42,然后递增 return .b。换句话说,它将打印 43.

如果您将 const 添加到转换中,您将得到一个编译器错误,例如:

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

所以这里 const 关键字很重要。

这将零初始化一个临时 struct x:

xx = (const struct x) {0};

然后该临时文件将用于复制分配 xx。无论临时对象是否为 const,它都会执行此操作。


一个流行的编译器 (gcc) 的示例表明,在 const 和非 const 的情况下,它将简单地将 xx 中的两个成员清零,而不实际上创建一个临时对象。编译后的程序表现得 就好像 一样:

xor     edx, edx
xor     esi, esi

C 2018 6.3.2.1 2 表示当任何对象在表达式中用作其值时,诸如 const 的限定符将被删除:

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.

因此,在xx = (const struct x) {0};中,(const struct x) {0};是一个创建const struct x对象的复合文字。但是,在获取此对象的值时,const 被删除,结果是 struct x 值。 (结构的“值”是其所有成员值的总和。)

因此,在这种使用中,const最终没有作用。但是,复合文字确实创建了一个 const 对象。这种效果可以在其他用途​​中看到。例如,使用 const struct x *p = & (const struct x) {0};,我们获取复合结构的地址。然后,如果我们尝试删除 const 并修改结构,如 ((struct x *) p)->a = 3;,C 标准未定义该行为。编译器可能已将该结构置于只读存储器中,并试图修改它可能会产生一个陷阱。或者,在优化期间,编译器可以使用结构是 const 的事实来忽略它可能更改的任何可能性。例如,在:

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

程序可能会打印“0”,因为在 printf 中的 p->a 中,编译器使用 p->a 被定义为 const 零这一事实.