Restrito ponteiro perguntas
-
25-09-2019 - |
Pergunta
Eu estou um pouco confuso sobre as regras relativas restrito ponteiros.Talvez alguém aí pode me ajudar.
É legal para definir aninhadas restrito ponteiros da seguinte forma:
int* restrict a; int* restrict b; a = malloc(sizeof(int)); // b = a; <-- assignment here is illegal, needs to happen in child block // *b = rand(); while(1) { b = a; // Is this legal? Assuming 'b' is not modified outside the while() block *b = rand(); }
É legal para derivar uma restrita valor do ponteiro da seguinte forma:
int* restrict c; int* restrict d; c = malloc(sizeof(int*)*101); d = c; for(int i = 0; i < 100; i++) { *d = i; d++; } c = d; // c is now set to the 101 element, is this legal assuming d isn't accessed? *c = rand();
Obrigado!André
Solução
Para referência, aqui está o restrict
qualificador é bastante complicada definição (a partir de C99 6.7.3.1 "definição Formal de restringir a"):
Deixa D ser uma declaração de uma ordinária identificador que fornece um meio de a designação de um objeto P como restringir-qualificado ponteiro para o tipo T.
Se D é apresentada dentro de um bloco e não tem classe de armazenamento externo, deixe-B denotam o bloco.Se D aparece na lista de parâmetro declarações de uma função definição, deixe-B denotam a associados do bloco.Caso, contrário, deixe a B indicar o bloco principal (ou o bloco de de qualquer que seja a função é chamada em programa de inicialização em um monobloco ambiente).
No que se segue, um ponteiro expressão E diz ser baseada em objeto P se (em algum ponto de seqüência na execução de B antes do avaliação de E) a modificação de P ao ponto de para uma cópia do objeto de matriz em qual anteriormente apontado iria mudar o valor de E.Note que o "baseado" é definido apenas para expressões com tipos de ponteiro.
Durante cada execução de B, deixe-L ser qualquer lvalue que tem &L com base em P.Se L é usado para acessar o valor de objeto X que ela designa, e X é também modificados (por qualquer meio), então o seguintes requisitos se aplicam:T deve não ser const qualificado.Todos os outros lvalue usado para acessar o valor de X deve também ter em seu endereço, com base no P.Cada acesso que modifica X são ser considerados, também, para modificar P, para os fins desta subcláusula.Se P é atribuído o valor de um ponteiro expressão E que é baseado em outro restrito ponteiro de objeto P2, associados com o bloco B2, em seguida, a execução de B2 deve começar antes a execução de B, ou a execução de B2 deve terminar antes a atribuição.Se estes requisitos não forem cumpridos, então o o comportamento é indefinido.
Aqui uma execução de B significa que parte da execução do programa que corresponderia ao vida útil de um objeto com tipo escalar e armazenamento automático de duração associado a B.
A minha leitura do acima significa que em sua primeira pergunta, a
não pode ser atribuída a b
, mesmo dentro de um "filho de" bloquear o resultado é indefinido.Tal atribuição pode ser feita se b
foram declaradas em que 'sub-bloco", mas desde que b
está declarada no mesmo âmbito, a
, a cessão não pode ser feita.
Para a pergunta 2, as atribuições entre c
e d
também resultar em comportamento indefinido (em ambos os casos).
O relevante pouco do padrão (para ambas as perguntas é:
Se P é atribuído o valor de um ponteiro de expressão E que é baseado no outro restrito ponteiro de objeto P2, associados com o bloco B2, em seguida, a execução de B2 deve começar antes a execução de B, ou a execução de B2 deve terminar antes a atribuição.
Desde que restritos os ponteiros são associados com o mesmo bloco, não é possível para o bloco B2 para começar antes da execução de B, ou para B2 para terminar antes da cessão (pois B e B2 são os mesmo bloco).
A norma dá um exemplo que faz isso muito claro (eu acho - a clareza da restrict
definição 4 parágrafos curtos par com C++'s regras de resolução de nome):
EXEMPLO 4:
A regra de limitação de atribuições entre restrito ponteiros não distinguir entre uma chamada de função e um equivalente bloco aninhado.Com uma exceção, apenas "o exterior-para-interior" de atribuições entre restrito ponteiros declarado em aninhadas blocos de comportamento definido.
{ int * restrict p1; int * restrict q1; p1 = q1; // undefined behavior { int * restrict p2 = p1; // valid int * restrict q2 = q1; // valid p1 = q2; // undefined behavior p2 = q2; // undefined behavior } }
Outras dicas
O restrict
o tipo de qualificador é um indicação para o compilador que, se a memória endereçada pelo restrict
-qualificado ponteiro é modificado, nenhum outro ponteiro irá aceder a essa mesma memória.O compilador pode escolher para otimizar o código envolvendo restrict
-qualificado ponteiros de uma forma que, caso contrário, poderia resultar em um comportamento incorreto. É responsabilidade do programador garantir que restringir-qualificados os ponteiros são utilizados como eles estavam destinados a ser utilizados.Caso contrário, o comportamento indefinido pode resultar. (link)
Como você pode ver a partir da descrição acima, ambas as designações são ilegais, que podem trabalhar em executáveis produzidos por alguns compiladores mas quebra em outros.Não espere que o compilador próprio para emitir avisos ou erros como restrict
apenas dá uma oportunidade para realizar determinadas de otimização, que podem optar por não realizar, como no caso de volatile
.