• Aucun résultat trouvé

Liaison externe et interne

Dans le document Apprenez le langage C (Page 75-80)

affecte leur visibilité sur différentes unités de traduction. Les objets avec liaison externe sont visibles dans toutes les autres unités de traduction (à condition que la déclaration appropriée soit incluse). Les objets avec liaison interne ne sont pas exposés à d'autres unités de traduction et ne peuvent être utilisés que dans l'unité de traduction où ils sont définis.

Examples

typedef

Définit un nouveau type basé sur un type existant. Sa syntaxe reflète celle d'une déclaration de variable.

/* Byte can be used wherever `unsigned char` is needed */ typedef unsigned char Byte;

/* Integer is the type used to declare an array consisting of a single int */ typedef int Integer[1];

/* NodeRef is a type used for pointers to a structure type with the tag "node" */ typedef struct node *NodeRef;

/* SigHandler is the function pointer type that gets passed to the signal function. */ typedef void (*SigHandler)(int);

Bien que ce ne soit pas techniquement une classe de stockage, un compilateur le traitera comme une classe, car aucune des autres classes de stockage n'est autorisée si le mot-clé typedef est utilisé.

Les typedef s sont importants et ne doivent pas être remplacés par la macro #define . typedef int newType;

newType *ptr; // ptr is pointer to variable of type 'newType' aka int

cependant,

#define int newType

newType *ptr; // Even though macros are exact replacements to words, this doesn't result to a pointer to variable of type 'newType' aka int

auto

Cette classe de stockage indique qu'un identifiant a une durée de stockage automatique. Cela signifie qu'une fois que l'étendue dans laquelle l'identifiant a été défini se termine, l'objet désigné par l'identifiant n'est plus valide.

Puisque tous les objets, ne vivant pas dans la portée globale ou étant déclarés static , ont une durée de stockage automatique par défaut lorsqu'ils sont définis, ce mot clé présente un intérêt historique et ne doit pas être utilisé:

int foo(void) {

/* An integer with automatic storage duration. */ auto int i = 3;

/* Same */ int j = 5; return 0;

} /* The values of i and j are no longer able to be used. */

statique

La classe de stockage static remplit différentes fonctions, en fonction de l'emplacement de la déclaration dans le fichier:

Pour confiner l'identifiant à cette unité de traduction uniquement (scope = fichier). /* No other translation unit can use this variable. */

static int i;

/* Same; static is attached to the function type of f, not the return type int. */ static int f(int n);

1.

Pour enregistrer des données à utiliser avec le prochain appel d'une fonction (scope = block):

void foo() {

static int a = 0; /* has static storage duration and its lifetime is the * entire execution of the program; initialized to 0 on * first function call */

int b = 0; /* b has block scope and has automatic storage duration and * only "exists" within function */

a += 10; b += 10;

printf("static int a = %d, int b = %d\n", a, b); } int main(void) { int i; for (i = 0; i < 5; i++) { foo(); } return 0; } Ce code imprime:

static int a = 10, int b = 10 2.

static int a = 20, int b = 10 static int a = 30, int b = 10 static int a = 40, int b = 10 static int a = 50, int b = 10

Les variables statiques conservent leur valeur même lorsqu'elles sont appelées depuis plusieurs threads différents.

C99

Utilisé dans les paramètres de fonction pour indiquer qu'un tableau doit avoir un nombre minimal constant d'éléments et un paramètre non nul:

/* a is expected to have at least 512 elements. */ void printInts(int a[static 512])

{

size_t i;

for (i = 0; i < 512; ++i) printf("%d\n", a[i]); }

Le nombre requis d'éléments (ou même un pointeur non nul) n'est pas nécessairement vérifié par le compilateur et les compilateurs ne sont pas tenus de vous informer de quelque manière que ce soit si vous ne disposez pas d'assez d'éléments. Si un programmeur

transmet moins de 512 éléments ou un pointeur nul, le comportement non défini est le résultat. Comme il est impossible d'appliquer cette règle, il faut faire particulièrement attention lors de la transmission d'une valeur pour ce paramètre à une telle fonction. 3.

externe

Utilisé pour déclarer un objet ou une fonction défini ailleurs (et qui a un lien externe ). En général, il est utilisé pour déclarer un objet ou une fonction à utiliser dans un module autre que celui dans lequel l'objet ou la fonction correspondant est défini:

/* file1.c */

int foo = 2; /* Has external linkage since it is declared at file scope. */

/* file2.c */ #include <stdio.h> int main(void) {

/* `extern` keyword refers to external definition of `foo`. */ extern int foo;

printf("%d\n", foo); return 0;

} C99

Les choses deviennent un peu plus intéressantes avec l'introduction du mot clé en inline dans C99:

/* Should usually be place in a header file such that all users see the definition */ /* Hints to the compiler that the function `bar` might be inlined */

/* and suppresses the generation of an external symbol, unless stated otherwise. */ inline void bar(int drink)

{

printf("You ordered drink no.%d\n", drink); }

/* To be found in just one .c file.

Creates an external function definition of `bar` for use by other files. The compiler is allowed to choose between the inline version and the external definition when `bar` is called. Without this line, `bar` would only be an inline function, and other files would not be able to call it. */

extern void bar(int);

registre

Des astuces pour le compilateur selon lesquelles l'accès à un objet doit être aussi rapide que possible. Si le compilateur utilise réellement le conseil est défini par l'implémentation; il peut simplement le traiter comme équivalent à auto .

La seule propriété qui est définitivement différente pour tous les objets déclarés avec register est que leur adresse ne peut pas être calculée. Ce register peut être un bon outil pour assurer

certaines optimisations: register size_t size = 467;

est un objet qui ne peut jamais créer d'alias car aucun code ne peut transmettre son adresse à une autre fonction où il pourrait être modifié de manière inattendue.

Cette propriété implique également qu'un tableau register int array[5];

ne peut pas se désintégrer en un pointeur vers son premier élément (c'est-à-dire que le array transforme en &array[0] ). Cela signifie que les éléments d'un tel tableau ne sont pas accessibles et que le tableau lui-même ne peut pas être transmis à une fonction.

En fait, la seule utilisation légale d'un tableau déclaré avec une classe de stockage de register est la sizeof opérateur; tout autre opérateur aurait besoin de l'adresse du premier élément du tableau. Pour cette raison, les tableaux ne devraient généralement pas être déclarés avec le mot-clé

register car cela les rend inutiles pour autre chose que le calcul de la taille du tableau entier, ce qui peut se faire aussi facilement sans le mot-clé register .

La classe de stockage des register est plus appropriée pour les variables définies dans un bloc et accessibles avec une fréquence élevée. Par exemple,

/* prints the sum of the first 5 integers*/ /* code assumed to be part of a function body*/ {

for(k = 1, sum = 0; k < 6; sum += k, k++); printf("\t%d\n",sum);

}

C11

L'opérateur _Alignof peut également être utilisé avec register tableaux de register .

Dans le document Apprenez le langage C (Page 75-80)