【发布时间】:2015-02-18 01:42:04
【问题描述】:
澄清:我的问题是:
- 使用
int类型的左值访问有效类型const int的对象是UB吗?
这个问题有两个代码示例,它们使用 int 类型的左值来访问有效类型 const int 的对象,我的目的是尽可能少地分心来实现这一点。如果除此特定问题之外还有其他任何 UB 来源,请发表评论,我将尝试更新代码示例。
下面是具体的代码示例供大家讨论:
#include <stdio.h>
#include <stdlib.h>
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 完全相同。
【问题讨论】:
-
为什么你需要 un-const 一个你只能读取的变量?
-
@StenSoft 我不需要需要,但知道这是否是 UB 会很有趣,并且在其他问题中也有相同的原则(例如推论我刚刚添加)
-
我可以肯定地告诉你,这在实践中可能行不通(在小型 POD 上抛弃 const)。当 GCC 将一个 const 字符放入寄存器时,我被它咬了一口,然后我厌倦了修改它:) 它导致了
SGIBUS或SIGTERM(它发生已经有几年了)。弄乱 const-ness 后果自负 :) -
@jww 修改它无疑是UB,但如果你只阅读它呢?
-
@user3386109 我想知道它是否违反了任何规则。我已经通过引用严格别名规则作为开始,因为它可能是候选规则,但我不想将讨论仅限于严格别名规则。在这个阶段,我认为这不值得提出两个单独的问题(1. 是否适用严格的别名规则,2. 是否有任何其他问题)因为我没有理由相信除了结构别名之外还有任何其他问题——但我可能是错的,我想让它开放给其他人提交任何东西。同意我们应该删除这些 cmets
标签: c language-lawyer strict-aliasing