É UB jogar fora const e ler valor? [duplicado]

Esta pergunta já tem uma resposta aqui:

A remoção de const de um ponteiro para const obedece estritamente alias em C e se refere ao mesmo objeto? 1 resposta

Esclarecimento: Minha pergunta é:

É UB usar um lvalue do tipoint acessar um objeto do tipo efetivoconst int ?

Esta pergunta possui dois exemplos de código que usam um lvalue do tipoint acessar um objeto do tipo efetivoconst int, e minha intenção é conseguir isso com o mínimo de distração possível. Se houver alguma outra fonte de UB além desse problema específico, deixe um comentário e tentarei atualizar o exemplo de código.

Aqui está um exemplo de código específico para discussão:

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

int main()
{
    const int c = 5;

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

A razão pela qual acho que pode ser UB é que a regra estrita de alias parece dizer que é UB:

C11 6.5 / 7

Um objeto deve ter seu valor armazenado acessado apenas por uma expressão lvalue que possui um dos seguintes tipos:

um tipo compatível com o tipo efetivo do objeto,uma versão qualificada de um tipo compatível com o tipo efetivo do objeto,...

otipo efetivo do objeto (6.5 / 6) aqui estáconst int.

Primeiro ponto:int econst int não sãotipos compatíveis (6.2.7 / 1, 6.7.3 / 10)

Segundo ponto:int parece não ser uma versão qualificada doconst int, porque não o produzimos adicionando qualificadores. No entanto, 6.2.5 / 26 não é claro:

Cada tipo não qualificado possui várias versões qualificadas de seu tipo, correspondentes às combinações de um, dois ou todos os três dos qualificadores const, voláteis e restritos. As versões qualificadas ou não qualificadas de um tipo são tipos distintos que pertencem à mesma categoria de tipo e têm os mesmos requisitos de representação e alinhamento. Um tipo derivado não é qualificado pelos qualificadores (se houver) do tipo do qual é derivado.

Ele não define o que é uma "versão qualificada deconst int"seria, apenas define o termo" versão qualificada "quando aplicado a um tipo não qualificado.

Segundo exemplo de código:

int *pc = malloc(sizeof *pc);
memcpy(pc, &c, sizeof c);
printf("%d\n", *pc);   // UB?

Desde amemcpy preserva o tipo efetivo (6.5 / 6), lendo através*pc tem exatamente a mesma interação com a regra estrita de aliasing que a leitura de*(int *)&c faz no primeiro exemplo.

questionAnswers(1)

yourAnswerToTheQuestion