É 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 respostaEsclarecimento: 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.