Partage via


Qualificateurs de type

Les qualificateurs de type fournissent une des deux propriétés à un identificateur. Le qualificateur de type const déclare un objet comme étant non modifiable. Le qualificateur de type volatile déclare un élément dont la valeur peut légitimement être modifiée par quelque chose non contrôlé par le programme dans lequel il apparaît, par exemple un thread s'exécutant simultanément.

Les qualificateurs de type, const, restrict et volatile, ne peuvent apparaître qu'une seule fois dans une déclaration. Ils peuvent apparaître avec n'importe quel spécificateur de type. Toutefois, ils ne peuvent pas apparaître après la première virgule dans une déclaration d'éléments multiples. Par exemple, les déclarations suivantes sont autorisées :

typedef volatile int VI;
const int ci;

Ces déclarations ne sont pas conformes :

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

Les qualificateurs de type sont appropriés uniquement lors de l'accès à des identificateurs sous la forme d'l-values dans des expressions. Consultez Expressions L-value et r-value pour plus d'informations sur les l-values et les expressions.

Syntaxe

type-qualifier:
const
restrict
volatile

const et volatile

Voici les déclarations const et volatile conformes :

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

Si la spécification d'un type tableau inclut des qualificateurs de type, l'élément est qualifié, pas le type tableau. Si la spécification du type de fonction comprend des qualificateurs, le comportement est non défini. volatile et const n’affectent pas la plage de valeurs ou les propriétés arithmétiques de l’objet.

  • Le mot clé const peut être utilisé pour modifier tout type fondamental ou d'agrégat, ou un pointeur vers un objet de tout type, ou un typedef. Si un élément est déclaré uniquement avec le qualificateur de type const, son type est considéré comme const int. Une variable const peut être initialisée ou être placée dans une région de stockage en lecture seule. Le mot clé const est utile pour déclarer des pointeurs vers const, car il interdit à la fonction de modifier le pointeur de quelque manière que ce soit.

  • Le compilateur suppose que, à tout moment dans le programme, une variable volatile est accessible par un processus inconnu qui utilise ou modifie sa valeur. Indépendamment des optimisations spécifiées sur la ligne de commande, le code pour chaque assignation ou référence d'une variable volatile doit être généré même s'il semble n'avoir aucun effet.

Si volatile est utilisé seul, int est pris par défaut. Le spécificateur de type volatile peut être utilisé pour fournir un accès fiable aux emplacements de mémoire spéciaux. Utilisez volatile avec des objets de données accessibles ou modifiables par les gestionnaires de signaux, en exécutant simultanément des programmes, ou par un matériel spécial tel que les registres de contrôle d'E/S mappé en mémoire. Vous pouvez déclarer une variable comme volatile pour toute sa durée de vie, ou vous pouvez effectuer un cast d'une référence unique pour qu'elle soit volatile.

  • Un élément peut être à la fois const et volatile, auquel cas il ne peut pas être légitimement modifié par son propre programme, mais par un processus asynchrone.

restrict

Le qualificateur de type restrict, introduit dans C99 et disponible en mode /std:c11 ou /std:c17, peut être appliqué aux déclarations de pointeur. Il qualifie le pointeur, pas ce sur quoi il pointe.

restrict est une indication d’optimisation à l’adresse du compilateur indiquant qu’aucun autre pointeur dans l’étendue actuelle ne fait référence au même emplacement de mémoire. Autrement dit, seul le pointeur ou une valeur dérivée de celui-ci (par exemple, pointeur + 1) est utilisé pour accéder à l’objet pendant la durée de vie du pointeur. Cela permet au compilateur de produire du code plus optimisé. C++ a un mécanisme équivalent, __restrict

N’oubliez pas que restrict est un contrat entre vous et le compilateur. Si vous aliassez un pointeur marqué avec restrict, le résultat n’est pas défini.

Voici un exemple qui utilise 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;
};

Voir aussi

/std (Spécifier la version du standard du langage)
Déclarations et types