UB是否可以抛弃const和读取值?

M.M*_*M.M 6 c strict-aliasing language-lawyer

澄清:我的问题是:

  • UB是否使用左值类型int来访问有效类型的对象const int

这个问题有两个代码示例,它们使用左值类型int来访问有效类型的对象const int,我的目的是尽可能少地分散对象.如果除了这个特定问题之外还有任何其他UB来源,请发表评论,我将尝试更新代码示例.


以下是讨论的具体代码示例:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    const int c = 5;

    printf("%d\n", *(int *)&c);
}
Run Code Online (Sandbox Code Playgroud)

我认为它可能是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?
Run Code Online (Sandbox Code Playgroud)

由于memcpy保留了有效类型(6.5/6),因此读取*pc与严格别名规则的完全相同,与*(int *)&c第一个示例中的读取操作完全相同.

Ste*_*oft 3

它不是。您发现的是为什么它不能被隐式转换。

[6.2.5/26] 指出:

每个非限定类型都有其类型的多个限定版本,对应于一个、两个或全部三个 const、volatile 和 limit 限定符的组合。类型的限定或非限定版本是属于同一类型类别并具有相同表示和对齐要求的不同类型。

(注:每个不合格类型。const int不是不合格而是int不合格。)

带脚注:

相同的表示和对齐要求意味着作为函数参数、函数返回值和联合成员的可互换性。

这意味着读取它将以相同的方式工作并产生相同的值。

[6.7.3/6]指定UB仅用于修改:

如果尝试通过使用非 const 限定类型的左值来修改使用 const 限定类型定义的对象,则行为未定义。


归档时间:

查看次数:

256 次

最近记录:

10 年,9 月 前