Pergunta

Eu estou um pouco confuso sobre as regras relativas restrito ponteiros.Talvez alguém aí pode me ajudar.

  1. É 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();
    }
    
  2. É 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é

Foi útil?

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top