UB是否会抛弃const和读取值?
澄清:我的问题是:
- UB是否使用
int
类型的左值来访问有效类型为const int
的对象?
这个问题有两个代码示例,它们使用类型为int
的左值来访问有效类型为const int
的对象,我的目的是尽可能少地分散对象。 如果除了这个特定问题之外还有任何其他UB来源,请发表评论,我将尝试更新代码示例。
以下是讨论的具体代码示例:
#include #include int main() { const int c = 5; printf("%d\n", *(int *)&c); }
我认为它可能是UB的原因是严格的别名规则似乎说它是UB:
C11 6.5 / 7
对象的存储值只能由具有以下类型之一的左值表达式访问:
- 与对象的有效类型兼容的类型,
- 与对象的有效类型兼容的类型的限定版本,
- …
这里对象的有效类型 (6.5 / 6)是const int
。
第一个要点: int
和const int
不兼容类型 (6.2.7 / 1,6.7.3 / 10)。
第二个要点: int
似乎不是const int
的限定版本,因为我们没有通过添加限定符来生成它。 但是6.2.5 / 26不清楚:
每个非限定类型都有几个类型的限定版本,对应于const,volatile和restrict限定符中的一个,两个或全部三个的组合。 类型的限定或非限定版本是属于相同类型类别且具有相同表示和对齐要求的不同类型。 派生类型不是由派生类型的限定符(如果有)限定的。
它没有定义“ const int
”的合格版本,它只在应用于非限定类型时定义术语“限定版本”。
第二个代码示例:
int *pc = malloc(sizeof *pc); memcpy(pc, &c, sizeof c); printf("%d\n", *pc); // UB?
由于memcpy
保留了有效类型(6.5 / 6),因此通过*pc
读取与严格别名规则完全相同,因为在第一个示例中通过*(int *)&c
读取。
它不是。 你发现的是为什么它不能被暗示。
[6.2.5 / 26]指出:
每个非限定类型都有几个类型的限定版本,对应于const,volatile和restrict限定符中的一个,两个或全部三个的组合。 类型的限定或非限定版本是属于相同类型类别且具有相同表示和对齐要求的不同类型。
(注意:每个非限定类型const int
不是不合格的,但int
是不合格的。)
用脚注:
相同的表示和对齐要求意味着可互换性作为函数的参数,函数的返回值和联合的成员。
这意味着读取它将以相同的方式工作并产生相同的值。
[6.7.3 / 6]仅指定UB进行修改:
如果尝试通过使用具有非const限定类型的左值来修改使用const限定类型定义的对象,则行为未定义。