Qualificadores de tipo

Os qualificadores de tipo fornecem uma de duas propriedades a um identificador. O qualificador de tipo const declara um objeto como não modificável. O qualificador de tipo volatile declara um item cujo valor possa ser alterado legitimamente para algo além do controle do programa em que aparece como um thread de execução simultânea.

Os qualificadores de tipo, const, restrict e volatile, podem aparecer apenas uma vez em uma declaração. Os qualificadores de tipo podem aparecer com qualquer especificador de tipo; porém, não podem aparecer depois da primeira vírgula em uma declaração de vários itens. Por exemplo, as seguintes declarações são aceitáveis:

typedef volatile int VI;
const int ci;

Essas declarações não são legais:

typedef int *i, volatile *vi;
float f, const cf;

Os qualificadores de tipo são relevantes apenas ao acessar identificadores como l-values nas expressões. Consulte Expressões L-Value e R-Value para obter informações sobre l-values e expressões.

Sintaxe

type-qualifier:
const
restrict
volatile

const e volatile

Os exemplos abaixo são declarações const e volatile legais:

int const *p_ci;      // Pointer to constant int
int const (*p_ci);   // Pointer to constant int
int *const cp_i;     // Constant pointer to int
int (*const cp_i);   // Constant pointer to int
int volatile vint;     // Volatile integer

Se a especificação de um tipo de matriz incluir qualificadores de tipo, o elemento será qualificada, não o tipo de matriz. Se a especificação de tipo de função incluir qualificadores, o comportamento será indefinido. volatile e const não afetam o alcance de valores ou propriedades aritméticas do objeto.

  • A palavra-chave const pode ser usada para modificar qualquer tipo fundamental ou de agregação, um ponteiro para um objeto de qualquer tipo ou um typedef. Se um item for declarado apenas com o qualificador de tipo const, seu tipo é considerado const int. Uma variável const pode ser inicializada ou pode ser colocada em uma região de armazenamento somente leitura. A palavra-chave const é útil para declarar ponteiros para const, pois isso requer que a função não altere o ponteiro de nenhuma maneira.

  • O compilador pressupõe que, a qualquer momento no programa, uma variável de volatile pode ser acessada por um processo desconhecido que usa ou modifica seu valor. Independentemente das otimizações especificadas na linha de comando, o código para cada atribuição ou referência a uma variável volatile deverá ser gerado mesmo se isso não tiver qualquer efeito aparente.

Se volatile for usado sozinho, int será presumido. O especificador de tipo volatile pode ser usado para fornecer acesso confiável aos locais especiais de memória. Use volatile com objetos de dados que possam ser acessados ou modificados por manipuladores de sinal, por programas de execução simultânea ou por hardware especial, como registros de controle de E/S mapeadas em memória. Você pode declarar uma variável como volatile para seu tempo de vida, ou você pode determinar que uma única referência seja volatile.

  • Um item pode ser const e volatile ao mesmo tempo. Nesse caso, ele não pode ser modificado legitimamente por seu próprio programa, mas pode ser modificado por algum processo assíncrono.

restrict

O qualificador de tipo restrict, introduzido em C99 e disponível no modo /std:c11 ou /std:c17, pode ser aplicado a declarações de ponteiro. Ele qualifica o ponteiro, não o que ele aponta.

restrict é uma dica de otimização para o compilador que nenhum outro ponteiro no escopo atual se refere ao mesmo local de memória. Ou seja, somente o ponteiro ou um valor derivado dele (como ponteiro + 1) é usado para acessar o objeto durante o tempo de vida do ponteiro. Isso ajuda o compilador a produzir um código mais otimizado. O C++ tem um mecanismo equivalente, __restrict

Tenha em mente que restrict é um contrato entre você e o compilador. Se você fizer um alias com um ponteiro marcado com restrict, o resultado será indefinido.

Veja um exemplo que usa restrict:

void test(int* restrict first, int* restrict second, int* val)
{
    *first += *val;
    *second += *val;
}

int main()
{
    int i = 1, j = 2, k = 3;
    test(&i, &j, &k);

    return 0;
}

// Marking union members restrict tells the compiler that
// only z.x or z.y will be accessed in any scope, which allows
// the compiler to optimize access to the members.
union z 
{
    int* restrict x;
    double* restrict y;
};

Confira também

/std (Especificar a versão padrão da linguagem)
Declarações e tipos