O seguinte uso do qualificador restrito em C é válido ou comportamento indefinido?
#include <stdio.h>
int foo(float * restrict a) {
float a1 = *a;
float a2 = *(a+1);
float * restrict c = a;
*c = 1;
*(c+1) = 2;
// are compilers obliged to load a[0] and a[1] again?
printf("%f %f\n",*a,*(a+1));
printf("%f %f\n",a1, a2);
}
Obrigado
O
restrict
qualificador dea
não está sendo violado.O
restrict
qualificador dea
não impede modificar o array por meio dec
em vez dea
, porque o valor dec
depende do valor dea
. Então você está modificando o array indiretamente por meio dea
, o que é permitido no que diz respeito aorestrict
qualificador dea
.O
restrict
qualificador dec
está sendo violado.§6.7.4.2 ¶4 da norma ISO C23 afirma o seguinte:
Nessa citação,
restrict
declaração do ponteiro, ou o bloco de função inteiro no caso de um parâmetro ser declarado com orestrict
qualificador,A frase
está sendo violado, porque na linha
o objeto referenciado X está sendo acessado por meio de
a
, ea
não depende dec
(c
depende dea
, mas não vice-versa).Os termos "depende de" e "baseado em" estão sendo usados por mim como sinônimos. A definição exata do termo "baseado em" neste contexto está em §6.7.4.2 ¶3 do padrão ISO C23:
Conclusão
Como o
restrict
qualificador dec
está sendo violado, o código postado tem comportamento indefinido. Se tivessea
sido declarado apenas com orestrict
qualificador ec
tivesse sido declarado sem esse qualificador, então o comportamento do programa teria sido bem definido.A declaração anterior é baseada na suposição de que
a
aponta para um array defloat
com pelo menos dois elementos. Se esse não for o caso, então o comportamento do programa também seria indefinido no caso especificado acima.O exemplo que você fornece resulta em Comportamento Indefinido porque você está dizendo ao compilador que o ponteiro restrito
a
não será associado a nenhum outro ponteiro (em termos mais simples: nenhum outro ponteiro ou variável acessa ou modifica a mesma região de memória) quando, em seu exemplo, você atribui a outrofloat * restrict
ponteiro o valor dea
, violando a semântica da palavra-chave restricted, pois ambosc
ea
são declarados como ponteiros restritos enquanto apontam para a mesma memória.Por que é UB?
Com o restricted, o compilador pode otimizar a função assumindo que
a
ec
nunca alias. Ele poderia, por exemplo, armazenar em cachea1
ea2
sem recarregá-los da memória após modificações por meio dec
. No entanto, como você modifica a memória apontada por ambosa
ec
, isso viola o contrato de restricted, e o comportamento do programa é indefinido.