• No se han encontrado resultados

Variables globales

In document CI 2125 Pensar En C Volumen 1 pdf (página 127-133)

3.6. Especificar la ubicación del espacio de almacenamiento

3.6.1. Variables globales

Las variables globales se definen fuera de todos los cuerpos de las funciones y están disponibles para todo el programa (incluso el código de otros ficheros). Las variables globales no están afectadas por ámbitos y están siempre disponibles (es decir, la vida de una variable global dura hasta la finalización del programa). Si la existencia de una variable global en un fichero se declara usando la palabra reserva- daexternen otro fichero, la información está disponible para su utilización en el segundo fichero. A continuación, un ejemplo del uso de variables globales:

//: C03:Global.cpp //{L} Global2

// Demonstration of global variables #include <iostream> using namespace std; int globe; void func(); int main() { globe = 12;

cout << globe << endl;

func(); // Modifies globe

cout << globe << endl; } ///:~

//: C03:Global2.cpp {O}

// Accessing external global variables extern int globe;

// (The linker resolves the reference)

void func() {

globe = 47; } ///:~

El espacio para la variableglobese crea mediante la definición enGlobal.cpp, y esa misma variable es accedida por el código deGlobal2.cpp. Ya que el código deGlobal2.cppse compila separado del código deGlobal.cpp, se debe informar al compilador de que la variable existe en otro sitio mediante la declaración

extern int globe;

Cuando ejecute el programa, observará que la llamada fun()afecta efectiva- mente a la única instancia global deglobe.

EnGlobal.cpp, se puede ver el comentario con una marca especial (que es di- seño mío):

//{L} Global2

Eso indica que para crear el programa final, el fichero objeto con el nombreGlobal2

debe estar enlazado (no hay extensión ya que los nombres de las extensiones de los ficheros objeto difieren de un sistema a otro). EnGlobal2.cpp, la primera lí- nea tiene otra marca especial{O}, que significa «No intentar crear un ejecutable de este fichero, se compila para que pueda enlazarse con otro fichero». El progra- maExtractCode.cppen el Volumen 2 de este libro (que se puede descargar de www.BruceEckel.com) lee estas marcas y crea elmakefileapropiado de modo que todo se compila correctamente (aprenderá sobre makefiles al final de este capítulo).

3.6.2. Variables locales

Las variables locales son las que se encuentran dentro de un ámbito; son «loca- les» a una función. A menudo se las llama variables automáticas porque aparecen automáticamente cuando se entra en un ámbito y desaparecen cuando el ámbito se acaba. La palabra reservadaautolo enfatiza, pero las variables locales sonautopor defecto, de modo que nunca se necesita realmente declarar algo comoauto.

Variables registro

Una variable registro es un tipo de variable local. La palabra reservadaregis- terindica al compilador «Haz que los accesos a esta variable sean lo más rápidos posible». Aumentar la velocidad de acceso depende de la implementación, pero, tal como sugiere el nombre, a menudo se hace situando la variable en un registro del microprocesador. No hay garantía alguna de que la variable pueda ser ubicada en un registro y tampoco de que la velocidad de acceso aumente. Es una ayuda para el compilador.

Hay restricciones a la hora de utilizar variables registro. No se puede consular o calcular la dirección de una variable registro. Una variable registro sólo se puede

3.6. Especificar la ubicación del espacio de almacenamiento

declarar dentro de un bloque (no se pueden tener variables de registro globales o estáticas). De todos modos, se pueden utilizar como un argumento formal en una función (es decir, en la lista de argumentos).

En general, no se debería intentar influir sobre el optimizador del compilador, ya que probablemente él hará mejor el trabajo de lo que lo pueda hacer usted. Por eso, es mejor evitar el uso de la palabra reservadaregister.

3.6.3. Static

La palabra reservada static tiene varios significados. Normalmente, las va- riables definidas localmente a una función desaparecen al final del ámbito de ésta. Cuando se llama de nuevo a la función, el espacio de las variables se vuelve a pedir y las variables son re-inicializadas. Si se desea que el valor se conserve durante la vida de un programa, puede definir una variable local de una función comostatic

y darle un valor inicial. La inicialización se realiza sólo la primera vez que se llama a la función, y la información se conserva entre invocaciones sucesivas de la función. De este modo, una función puede «recordar» cierta información entre una llamada y otra.

Puede surgir la duda de porqué no utilizar una variable global en este caso. El encanto de una variable statices que no está disponible fuera del ámbito de la función, de modo que no se puede modificar accidentalmente. Esto facilita la locali- zación de errores.

A continuación, un ejemplo del uso de variablesstatic: //: C03:Static.cpp

// Using a static variable in a function #include <iostream>

using namespace std;

void func() {

static int i = 0;

cout << "i = " << ++i << endl; }

int main() {

for(int x = 0; x < 10; x++) func();

} ///:~

Cada vez que se llama afunc()dentro del bucle, se imprime un valor diferente. Si no se utilizara la palabra reservadastatic, el valor mostrado sería siempre1.

El segundo significado destaticestá relacionado con el primero en el sentido de que «no está disponible fuera de cierto ámbito». Cuando se aplica statical nombre de una función o de una variable que está fuera de todas las funciones, significa «Este nombre no está disponible fuera de este fichero». El nombre de la función o de la variable es local al fichero; decimos que tiene ámbito de fichero. Como demostración, al compilar y enlazar los dos ficheros siguientes aparece un error en el enlazado:

//: C03:FileStatic.cpp

// linking this file with FileStatic2.cpp // will cause a linker error

// File scope means only available in this file: static int fs;

int main() {

fs = 1; } ///:~

Aunque la variablefsestá destinada a existir como unexternen el siguiente fi- chero, el enlazador no la encontraría porque ha sido declaradastaticenFileStatic. cpp. //: C03:FileStatic2.cpp {O} // Trying to reference fs extern int fs; void func() { fs = 100; } ///:~

El especificadorstatictambién se puede usar dentro de una clase. Esta expli- cación se dará más adelante en este libro, cuando aprenda a crear clases.

3.6.4. extern

La palabra reservadaexternya ha sido brevemente descripta. Le dice al com- pilador que una variable o una función existe, incluso si el compilado aún no la ha visto en el fichero que está siendo compilado en ese momento. Esta variable o fun- ción puede definirse en otro fichero o más abajo en el fichero actual. A modo de ejemplo:

//: C03:Forward.cpp

// Forward function & data declarations #include <iostream>

using namespace std;

// This is not actually external, but the // compiler must be told it exists somewhere: extern int i;

extern void func();

int main() {

i = 0; func(); }

int i; // The data definition

void func() {

i++; cout << i; } ///:~

3.6. Especificar la ubicación del espacio de almacenamiento

Cuando el compilador encuentra la declaraciónextern int isabe que la de- finición paraidebe existir en algún sitio como una variable global. Cuando el com- pilador alcanza la definición dei, ninguna otra declaración es visible, de modo que sabe que ha encontrado la mismaideclarada anteriormente en el fichero. Si se hu- biera definidoicomostatic, estaría indicando al compilador queise define glo- balmente (porextern), pero también que tiene el ámbito de fichero (porstatic), de modo que el compilador generará un error.

Enlazado

Para comprender el comportamiento de los programas C y C++, es necesario saber sobre enlazado. En un programa en ejecución, un identificador se representa con espacio en memoria que aloja una variable o un cuerpo de función compilada. El enlazado describe este espacio tal como lo ve el enlazador. Hay dos formas de enlazado:enlace internoyenlace externo.

Enlace interno significa que el espacio se pide para representar el identificador só- lo durante la compilación del fichero. Otros ficheros pueden utilizar el mismo nom- bre de identificador con un enlace interno, o para una variable global, y el enlazador no encontraría conflictos - se pide un espacio separado para cada identificador. El enlace interno se especifica mediante la palabra reservadastaticen C y C++.

Enlace externo significa que se pide sólo un espacio para representar el identifi- cador para todos los ficheros que se estén compilando. El espacio se pide una vez, y el enlazador debe resolver todas las demás referencias a esa ubicación. Las variables globales y los nombres de función tienen enlace externo. Son accesibles desde otros ficheros declarándolas con la palabra reservadaextern. Por defecto, las variables definidas fuera de todas las funciones (con la excepción deconsten C++) y las defi- niciones de las funciones implican enlace externo. Se pueden forzar específicamente a tener enlace interno utilizandostatic. Se puede establecer explícitamente que un identificador tiene enlace externo definiéndolo comoextern. No es necesario defi- nir una variable o una función comoexternen C, pero a veces es necesario para

consten C++.

Las variables automáticas (locales) existen sólo temporalmente, en la pila, mien- tras se está ejecutando una función. El enlazador no entiende de variables automáti- cas, de modo que no tienen enlazado.

3.6.5. Constantes

En el antiguo C (pre-Estándar), si se deseaba crear una constante, se debía utilizar el preprocesador:

#define PI 3.14159

En cualquier sitio en el que utilizase PI, el preprocesador lo substituía por el valor 3.14159 (aún se puede utilizar este método en C y C++).

Cuando se utiliza el preprocesador para crear constantes, su control queda fuera del ámbito del compilador. No existe ninguna comprobación de tipo y no se puede obtener la dirección de PI (de modo que no se puede pasar un puntero o una re- ferencia a PI). PI no puede ser una variable de un tipo definido por el usuario. El significado de PI dura desde el punto en que es definida, hasta el final del fichero; el preprocesador no entiende de ámbitos.

C++ introduce el concepto de constantes con nombre que es lo mismo que va- riable, excepto que su valor no puede cambiar. El modificadorconstle indica al compilador que el nombre representa una constante. Cualquier tipo de datos prede- finido o definido por el usuario, puede ser definido comoconst. Si se define algo comoconsty luego se intenta modificar, el compilador generará un error.

Se debe especificar el tipo de unconst, de este modo:

const int x = 10;

En C y C++ Estándar, se puede usar una constante en una lista de argumentos, incluso si el argumento que ocupa es un puntero o una referencia (p.e, se puede obtener la dirección de una constante). Las constantes tienen ámbito, al igual que una variable ordinaria, de modo que se puede «esconder» una constante dentro de una función y estar seguro de que ese nombre no afectará al resto del programa.

constha sido tomado de C++ e incorporado al C Estándar pero un modo un poco distinto. En C, el compilador trata aconstdel mismo modo que a una variable que tuviera asociado una etiqueta que dice «No me cambies». Cuando se define un

consten C, el compilador pide espacio para él, de modo que si se define más de un

constcon el mismo nombre en dos ficheros distintos (o se ubica la definición en un fichero de cabeceras), el enlazador generará mensajes de error sobre del conflicto. El concepto deconsten C es diferente de su utilización en C++ (en resumen, es más bonito en C++).

Valores constantes

En C++, una constante debe tener siempre un valor inicial (En C, eso no es cierto). Los valores de las constantes para tipos predefinidos se expresan en decimal, octal, hexadecimal, o números con punto flotante (desgraciadamente, no se consideró que los binarios fuesen importantes), o como caracteres.

A falta de cualquier otra pista, el compilador assume que el valor de una cons- tante es un número decimal. Los números 47, 0 y 1101 se tratan como números deci- males.

Un valor constante con un cero al principio se trata como un número octal (base 8). Los números con base 8 pueden contener únicamente dígitos del 0 al 7; el compi- lador interpreta otros dígitos como un error. Un número octal legítimo es 017 (15 en base 10).

Un valor constante con0x al principio se trata como un número hexadecimal (base 16). Los números con base 16 pueden contener dígitos del 0 al 9 y letras de la a a la f o A a F. Un número hexadecimal legítimo es 0x1fe (510 en base 10).

Los números en punto flotante pueden contener comas decimales y potencias exponenciales (representadas mediantee, lo que significa «10 elevado a»). Tanto el punto decimal como laeson opcionales. Si se asigna una constante a una variable de punto flotante, el compilador tomará el valor de la constante y la convertirá a un número en punto flotante (este proceso es una forma de lo que se conoce como conversión implícita de tipo). De todos modos, es una buena idea el usar el punto decimal o una epara recordar al lector que está utilizando un número en punto flotante; algunos compiladores incluso necesitan esta pista.

Algunos valores válidos para una constante en punto flotante son: 1e4, 1.0001, 47.0, 0.0 y 1.159e-77. Se pueden añadir sufijos para forzar el tipo de número de pun- to flotante:f oFfuerza que sea float,Lol fuerza que sea un long double; de lo

In document CI 2125 Pensar En C Volumen 1 pdf (página 127-133)