[WikiItic] [TitleIndex] [WordIndex

Consideracions sobre les variables globals a C99

Reglamentació normativa

Resum del que diu l'estàndard C99 sobre compartició de variables i també de http://publications.gbdirect.co.uk/c_book/chapter8/declarations_and_definitions.html

Declaració i definició

  1. Una declaració és una sentència que especifica la interpretació i els atributs d'un conjunt d'identificadors.

  2. Una declaració és també una definició quan:

    1. En el cas d'un objecte implica la reserva de memòria.
    2. En el cas d'una funció inclou el cos.

Definició externa

  1. Una definició externa (ATENCIÓ: no s'ha de confondre amb external linkage) és aquella que té lloc en l'àmbit del fitxer.
  2. No pot haver-hi més d'una definició externa d'un identificador amb linkage intern.

  3. Una declaració d'un objecte amb inicialitzador en l'àmbit d'un fitxer és una definició externa.
  4. Una declaració d'un objecte en l'àmbit d'un fitxer que no té inicialització i:
    1. No té especificador, o bé
    2. Té l'especificador static.

    és una definició temptativa.

  5. Si un fitxer conté una o més definicions temptatives del mateix identificador llavors es comporta com si existís una definició de l'identificador amb un inicialitzador igual a 0.

Linkage

  1. Linkage (6,2,2). Procés a través del qual un identificador declarat en diferents àmbits o declarat més d'una vegada en un sol àmbit pot ésser forçat el mateix objecte o funció. Hi ha tres tipus possibles de linkage:

    1. Intern. En el context d'un fitxer, tota declaració d'un objecte o

      funció amb linkage intern denota la mateixa entitat.

    2. Extern. En el context dels fitxers que formen un programa, tota

      declaracio d'un objecte o funció amb linkage extern denota la mateixa entitat.

    3. Nul. Tot objecte la declaració del qual te linkage nul denota una entitat única.

  2. Tot identificador declarat en l'àmbit d'un fitxer amb l'especificador

    'static' té linkage intern.

  3. Un identificador declarat amb l'especificador 'extern' en qualsevol àmbit que:
    1. Si l'identificador no tenia cap altra declaració prèvia llavors

      aquest identificador té linkage extern.

    2. Si l'identificador tenia alguna declaració prèvia i no

      especificava cap tipus de linkage llavors aquest identificador linkage extern.

    3. Si l'identificador tenia una o més declaracions prèvies que

      especificaven un linkage extern o intern, llavors aquest identificador té el linkage que s'havia definit prèviament.

  4. Si una funció no té especificador, el seu linkage es determina com si tingués especificador 'extern'.

  5. La declaració d'un identificador en l'àmbit fitxer es considera que

    linkage extern.

Patrons de treball habituals

Variable global privada d'un mòdul

Patró

Un patró molt corrent és aquell en que en un mòdul d'un programa concret es necessària una variable global en l'àmbit del mòdul però privada de cara a altres mòduls. Habitualment, ho implementem declarant aquesta variable com static en la implementació d'aquest mòdul.

Prenguem com exemple el mòdul modul amb els seus dos fitxers modul.h i modul.c. Suposem que la variable global del mòdul és int a. Llavors aquesta variable la definiriem exclusivament en el fitxer modul.c així:

   1 #include "modul.h"
   2 
   3 static int a;
   4 
   5 int consulta(void) {
   6    return a;
   7 }
   8 
   9 /* més funcions si escau */

Rationale

Noteu que la declaració d'a és una 'definició temptativa' i, per tant és com si haguessim usat la definició

   1 static int a = 0;

D'altra banda, com està declarat en l'àmbit del fitxer i té el modificador static té linkatge 'intern'. Per tant mai serà compartida per cap altre mòdul.

En conseqüència és una variable global del mòdul i privada d'aquest.

Variable global compartida entre mòduls

Patró

En aquest cas tenim un programa composat de diversos mòduls. Per exemple: m1 i m2. Tenim també una variable global int c que volem compartir entre tots els mòduls però definir només en el mòdul m1. En aquest cas el patró de treball habitual és dissenyar els mòduls de la següent forma:

El mòdul m1:

   1 /* m1.h */
   2 #ifndef M1_H
   3 #define M1_H
   4 
   5 extern int c;
   6 
   7 int perdos(void);
   8 
   9 /* altres prototips i constants que el mòdul exporta */
  10 #endif
  11 

   1 /* m1.c */
   2 #include "m1.h"
   3 
   4 int c;
   5 
   6 int perdos(void) {
   7    return c * 2;
   8 }
   9 
  10 
  11 /* altres funcions del mòdul */

Pel que fa al mòdul m2:

   1 /* m2.h */
   2 #ifndef M2_H
   3 #define M2_H
   4 
   5 int pertres(void);
   6 
   7 /* altres prototips i constants que el mòdul exporta */
   8 #endif
   9 

   1 /* m2.c */
   2 #include "m1.h"
   3 #include "m2.h"
   4 
   5 int pertres(void) {
   6    return c * 3;
   7 }
   8 
   9 /* implementacions de funcions que usen també la
  10    variable c */

Rationale

Si analitzem la unitat de compilació del mòdul m1 veiem que, a causa de l'#include, hi ha dues declaracions seguides de la variable c:

extern int c;
int c;

La primera és una simple declaració i la segona una definició temptativa, que es consolida com a definició equivalent a int i = 0. D'acord amb al norma, aquesta declaració té linkage 'extern'. Concloent: a m1 es defineix l'objecte c amb linkatge extern.

Si analitzem m2 veiem que només es troba amb la definició extern int c. En aquest cas es tracta d'una declaració (no definició) d'un objecte amb linkage 'extern'.

Considerant ambdós mòduls, tenim una sola definició de c a m1 i dues definicions a m1 i m2 que, en ser amb linkage 'extern', referencien un únic objecte. És a dir, c és un sol objecte compartit entre m1 i m2 i definit a m1.


2023-07-03 11:46