C 是否要抛弃常量并读取值?

C 是否要抛弃常量并读取值?,c,language-lawyer,strict-aliasing,C,Language Lawyer,Strict Aliasing,澄清:我的问题是: 是否使用类型为int的左值访问有效类型为const int的对象 这个问题有两个代码示例,它们使用类型为int的左值来访问有效类型为const int的对象,我的目的是尽可能少地分散注意力来实现这一点。如果有任何其他来源的UB除了这个特定的问题,请留下评论,我会尝试更新代码样本 下面是一个具体的代码示例供讨论: #include <stdio.h> #include <stdlib.h> int main() { const int c

澄清:我的问题是:

  • 是否使用类型为
    int
    的左值访问有效类型为
    const int
    的对象
这个问题有两个代码示例,它们使用类型为
int
的左值来访问有效类型为
const int
的对象,我的目的是尽可能少地分散注意力来实现这一点。如果有任何其他来源的UB除了这个特定的问题,请留下评论,我会尝试更新代码样本


下面是一个具体的代码示例供讨论:

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

int main()
{
    const int c = 5;

    printf("%d\n", *(int *)&c);
}

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

。您所发现的是它不能隐式转换的原因

[6.2.5/26]指出:

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

(注意:每个不合格类型。
const int
不合格,但
int
不合格。)

附脚注:

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

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

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

如果试图通过使用具有非常量限定类型的左值来修改使用常量限定类型定义的对象,则该行为是未定义的


为什么您需要对一个只读取的变量进行反常量计算?@StenSoft我不需要,但知道这是否为反常量会很有趣,同样的原则也适用于其他问题(例如,我刚才添加的推论),我可以肯定地告诉您,这在实践中可能不起作用(在一个小豆荚上丢弃常量)。当GCC在寄存器中放入一个常量字符时,我被它吓了一跳,然后我就开始修改它:)它导致了一个
SGIBUS
SIGTERM
(它已经发生几年了)。弄乱常量会有你自己的危险:)@jww毫无疑问修改它是UB,但是如果你只看它会怎么样?@user3386109我想知道它是否违反了任何规则。我首先引用了严格别名规则,因为它可能是一个候选规则,但我不想将讨论局限于严格别名规则。在这个阶段,我觉得它不值得问两个独立的问题(1.严格的别名规则是否适用,2.是否存在任何其他问题),因为我没有理由相信除了结构别名之外还有任何其他ISSI——但我可能错了,我想让其他人提交任何内容。同意我们应该删除这些注释。注释是非规范性的,但在任何情况下,我们都不是在讨论函数的参数、函数的返回值或联合的成员,因此我不知道这是如何应用的,也不知道您如何从中得出阅读必须正确的结论。您如何看待使用
volatile
而不是
const
的等效问题?它具有相同的表示和对齐要求,因此您应该能够以相同的方式阅读它。脚注有助于理解其背后的原因。对于volatile,[6.7.3/6]规定,对volatile的任何非volatile引用都是UB。关于6.7.3/6中明确禁止volatile,我已经从我的问题中删除了这一段,你是说严格的别名规则有缺陷的文本,还应该包括通过“任何具有相同表示和对齐要求的内容”?它确实违反了严格的别名规则。但只有当值发生更改(重新排序读取是安全的)时,别名才能触发UB,这将导致UB。
int *pc = malloc(sizeof *pc);
memcpy(pc, &c, sizeof c);
printf("%d\n", *pc);   // UB?