Logo

Marco Cantù
Pascal Esencial 

Capítulo 3 Actualizar
Tipos, variables y constantes 

El lenguaje Pascal original estaba basado en algunas nociones simples, que ahora se han hecho bastante comunes entre los lenguajes de programación. La primera noción es la de tipo de datos. El tipo determina los valores que puede tomar una variable, y las operaciones que se pueden realizar sobre ella. El concepto de tipo es más fuerte en Pascal que en C, donde los tipos de datos aritméticos son casi intercambiables, y mucho más fuertes que en las versiones originales de BASIC, donde no existía concepto similar alguno.

Variables

Pascal requiere que todas las variables sean declaradas antes de ser utilizadas. Cada vez que declare una variable, deberá especificar un tipo de dato. Siguen algunas declaraciones :

var
  Valor: Integer;
  EsCorrecto: Boolean;
  A, B: Char;

La palabra clave var puede utilizarse en varios lugares del código, como el principio del código de una función o procedimiento, para declarar variables que son locales en la rutina, o dentro de una unidad, para declarar variables globales. Después de la palabra var viene una lista de nombres de nuevas variables, seguidas de dos puntos y el nombre del tipo de dato. Puede escribir más de una variable en una misma línea, como en la última instrucción del ejemplo anterior.

Una vez que haya definido la variable de un tipo determinado, puede realizar sobre ella las operaciones permitidas para aquel tipo de dato. Por ejemplo, se puede utilizar valores booleanos para comprobaciones (sí/no) y valores enteros en una expresión numérica. Sin embargo, no se puede mezclar booleanos con enteros (como sí se puede en el lenguaje C).

Con asignaciones simples, podemos escribir código como el siguiente :

Valor := 10;
EsCorrecto := True;

Pero la siguiente instrucción no es válida, porque las variables implicadas son de tipos de dato distintos :

Valor := EsCorrecto; // error

Si intenta compilar este código, Delphi produce un error con la descripción : Incompatible types: 'Integer' and 'Boolean'. Normalmente, errores como estos son errores de programación, porque no tiene sentido asignar un valor True (verdadero) o False (falso) a una variable de tipo entero. No le eche la culpa a Delphi de estos errores. Sólo le está advirtiendo de que hay algo equivocado en el código.

Por supuesto, a menudo es posible convertir el valor de una variable de un tipo a otro. En algunos casos, esta conversión es automática, pero en general tendrá que hacer una llamada a una función específica del sistema que cambia la representación interna de los datos.

En Delphi puede asignar un valor inicial a una variable global cuando la declara. Por ejemplo :

var
  Valor: Integer = 10;
  Correcto: Boolean = True;

Esta técnica de inicialización funciona sólo en variables globales, no en variables definidas en el interior de un procedimiento o método.

Constantes

Pascal también permite la declaración de constantes, para nombrar valores que no cambian durante la ejecución del programa. Para declarar una constante, no necesita especificar un tipo de dato, sino sólo asignar un valor inicial. El compilador examinará el valor y usará el tipo de dato adecuado, automáticamente. Siguen algunos ejemplos :

const
  Millar = 1000;
  Pi = 3.14;
  NombreAutor = 'Marco Cantù';

Delphi determina el tipo de dato de la constante de acuerdo con su valor. En el ejemplo anterior, la constante Millar se supone que es del tipo SmallInt, el tipo de entero más pequeño en que cabe el valor 1000. Sin embargo, si quiere usted decirle a Delphi que use un tipo específico, puede incluir el nombre del tipo en la declaración :

const
  Millar: Integer = 1000;

Cuando usted declara una constante, el compilador puede elegir entre asignarle una posición en la memoria y guardar su valor allí, o duplicar el valor actual cada vez que se usa la constante. Este segundo modo de funcionamiento tiene sentido especialmente en el uso de constantes simples :

Nota: La versión en 16 bits de Delphi permite modificar el valor de una constante durante la ejecución, como si fuera una variable. La versión en 32 bits aún permite este comportamiento para garantizar la retrocompatibilidad, cuando se habilita la directiva $J del compilador o se activa la casilla Assignable typed constants de la página Compiler del cuadro de diálogo Project Options. Aunque este es el valor por defecto, se aconseja enérgicamente no utilizar este truco como técnica de programación habitual. Asignar un nuevo valor a una constante desactiva todas las optimizaciones previstas en el compilador para el manejo de constantes. En tales casos, decántese por una variable.

Constantes de cadena de recursos (Resource String Constants)

Cuando defina una constante de cadena, en vez de escribir :

const
  AuthorName = 'Marco Cantù';

desde Delphi 3 puede escribir :

resourcestring
  AuthorName = 'Marco Cantù';

En ambos casos se está definiendo una constante, esto es, un valor que no va a cambiar durante la ejecución del programa. La diferencia consiste en la implementación. Una constante de cadena definida con la directiva resourcestring se almacena en los recursos del programa, en una tabla de cadenas de caracteres.

Para ver cómo funciona esto, puede examinar el ejemplo ResStr example, que tiene un botón con el siguiente código :

resourcestring
  AuthorName = 'Marco Cantù';
  BookName = 'Essential Pascal';

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage (BookName + #13 + AuthorName);
end;

Las salidas de las dos cadenas aparecen en líneas separadas, porque las cadenas van separadas por el carácter de nueva línea (indicado por su valor numérico #13 como constante de tipo carácter).

El aspecto interesante de este programa es que si lo examina con un explorador de recursos (hay uno disponible entre los ejemplos que se suministran con Delphi), verá las nuevas cadenas entre los recursos. Esto significa que las cadenas no son parte del código compilado, sino que son almacenadas en una área separada del ejecutable (el archivo exe).

Nota: En resumen, la ventaja de los recursos es un manejo eficiente de la memoria, realizado por Windows, y también la posibilidad de localizar un programa (traduciendo las cadenas a otro lenguaje) sin tener que modificar su código fuente.

Tipos de datos

En Pascal hay varios tipos de datos predefinidos, que pueden ser divididos en tres grupos: tipos ordinales, tipos reales y cadenas. Trataremos sobre los tipos ordinal y real en las próximas secciones, mientras que las cadenas se mencionarán más adelante en este mismo capítulo. En esta sección también introduciré algunos tipos definidos por las bibliotecas de Delphi (no predefinidas por el compilador), que pueden considerarse tipos predefinidos.

Delphi también incluye un tipo de datos sin tipo, llamado variante, que discutiremos el Capítulo 10 de este libro). Resulta extraño que exista el variante, que no pasa por una comprobación de tipo lo bastante fuerte. Fue introducido en Delphi 2 para poder manejar la automatización OLE.

Tipos ordinales

Los tipos ordinales están basados en el concepto de orden o secuencia. Usted no sólo puede comparar dos valores para ver cuál es más alto, sino que también puede pedir el valor que sigue o precede a un valor dado, o calcular el valor más bajo o alto de los posibles.

Los tipos ordinales predefinidos más importantes son entero (Integer), booleano (Boolean) y carácter (Char[acter]). De cualquier manera, hay muchos tipos relacionados que tienen el mismo significado, pero una representación interna y un rango de valores distintos. La tabla 3.1 que sigue muestra los tipos de datos ordinales utilizados para representar números.

Tabla 3.1: Tipos de datos ordinales para números

Tamaño 

Rango con signo (positivo / negativo) 

Rango sin signo 

8 bits ShortInt (entero corto)
de -128 a 127
Byte
de 0 a 255
16 bits SmallInt (entero pequeño)
de -32.768 a 32.767
Word (palabra)
de 0 a 65.535
32 bits LongInt (entero largo)
de -2.147.483,648 a 2.147.483.647
LongWord (palabra larga) (desde Delphi 4)
de 0 a 4.294,967,295
64 bits Int64 (entero de 64 bits)  
16/32 bits Integer (entero) Cardinal

Como puede ver, estos tipos corresponden a diferentes representaciones de números, dependiendo del número de bits usado para expresar el valor, y la presencia o ausencia de un bit de signo. Los valores con signo pueden ser positivos o negativos, pero tienen un rango más estrecho de valores, porque hay un bit menos disponible para el valor en sí. Puede remitirse al ejemplo sobre el Rango, discutido en la sección siguiente, para averiguar el rango de valores que corresponden a cada tipo.

El último grupo (marcado como 16/32) indica valores que tienen una representación distinta en las versiones de 16 bits y 32 bits de Delphi. Los tipos Integer y Cardinal son usados frecuentemente, porque corresponden a la representación nativa de números en la CPU.

Tipos enteros en Delphi 4

En Delphi 3, los números sin signo de 32 bits indicados por el tipo Cardinal eran, en realidad, valores de 31 bits, con un rango de hasta 2 megabytes. Delphi 4 introdujo un nuevo tipo numérico sin signo, LongWord, que usa un valor de 32 bits auténtico, de hasta 4 megabytes. El tipo Cardinal es ahora un alias del nuevo tipo LongWord. LongWord permite acceder a 2 MB de datos más a través de un número sin signo, como se menciona arriba. Además, corresponde a la representación nativa de números en la CPU.

Otro tipo introducido por primera vez en Delphi 4 es el tipo Int64, que representa números enteros de hasta 18 dígitos. Este nuevo tipo es totalmente compatible con algunas de las rutinas de tipo ordinal (como High y Low), rutinas numéricas (como Inc y Dec), y rutinas de conversión de cadena (como IntToStr). Para la conversión contraria, de cadena a número, hay dos funciones específicas : StrToInt64 y StrToInt64Def.

Booleanos

Valores booleanos distintos del tipo Boolean se utilizan muy poco. Las funciones API de Windows requieren algunos valores booleanos con representaciones específicas. Los tipos son ByteBool, WordBool y LongBool.

En Delphi 3, para conseguir compatibilidad con Visual Basic y automatización OLE, los tipos de datos ByteBool, WordBool y LongBool fueron modificados para representar el valor True con -1, mientras que el valor False es aún 0. El tipo de datos Boolean se mantiene invariable (True es 1, False es 0). Si usted ha utilizado typecasts (moldeadores de tipo) específicos en su código Delphi 2, portar el código a versiones posteriores de Delphi puede causarle errores.

Caracteres

Finalmente, hay dos representaciones de caracteres : ANSIChar y WideChar. El primer tipo representa caracteres de 8-bits, correspondientes al conjunto de caracteres ANSI usado tradicionalmente por Windows; el segundo representa caracteres de 16 bits, que corresponden a los nuevos caracteres Unicode accesibles en Windows NT, y sólo parcialmente por Windows 95 y 98. La mayor parte del tiempo, usted sólo utilizará el tipo Char, que en Delphi 3 corresponde a ANSIChar. Tenga presente, en cualquier caso, que los 256 primeros caracteres Unicode corresponden exactamente a los caracteres ANSI.

Los caracteres constantes pueden ser representados con su notación simbólica, p. ej. 'k', o con una notación numérica, como en #78. Este último también puede ser representado utilizando la función Chr, como en Chr (78). La conversión recíproca puede hacerse mediante la función Ord.

En general es mejor utilizar la notación simbólica cuando se indican letras, dígitos o símbolos. Para referirse a caracteres especiales, sin embargo, normalmente usará la notación numérica. La siguiente lista incluye algunos de los caracteres especiales más usados :

El ejemplo sobre el Rango

Para darle una idea de los distintos rangos de algunos de los tipos ordinales, he escrito un programa Delphi sencillo llamado Range. Algunos resultados se muestran en la figura 3.1.

Figura 3.1: El ejemplo Range muestra alguna información sobre tipos de datos ordinales (en este caso, del tipo Integer).

El programa Range está basado en un formulario sencillo, que tiene seis botones (cada uno lleva el nombre de un tipo de datos ordinal), y algunas etiquetas sobre categorías de información, como se ve en la figura. Algunas de las etiquetas se usan para incluir texto estático, y otras para mostrar la información sobre el tipo cada vez que se pulsa uno de los botones.

Cada vez que el usuario pulsa uno de los botones de la derecha, el programa actualiza las etiquetas como salida. Distintas etiquetas muestran el tipo de dato, el número de bytes utilizado y los valores máximo y mínimo que puede almacenar ese tipo de datos. Cada botón tiene su propio método de respuesta a eventos tipo OnClick, porque el código usado para calcular los tres valores varía ligeramente de un botón a otro. Por ejemplo, aquí está el código fuente del evento OnClick para el botón Integer (BtnInteger):

procedure TFormRange.BtnIntegerClick(Sender: TObject);
begin
  LabelType.Caption := 'Integer';
  LabelSize.Caption := IntToStr (SizeOf (Integer));
  LabelMax.Caption := IntToStr (High (Integer));
  LabelMin.Caption := IntToStr (Low (Integer));
end;

Si tiene algo de experiencia en la programación en Delphi, puede examinar el código fuente del programa para entender cómo funciona. Para principiantes, es suficiente con darse cuenta del uso de tres funciones : SizeOf (tamaño de), High (alto) y Low (bajo). Los resultados de las dos últimas funciones son ordinales del mismo tipo (en este caso, enteros), y el resultado de la función SizeOf es siempre un entero. El valor de salida de cada una de estas funciones se traduce primero en cadenas utilizando la función IntToStr, y luego se copia en los títulos de las tres etiquetas.

Los métodos asociados con los otros botones son muy similares al mencionado arriba. La única diferencia radica en el tipo de dato que se pasa como parámetro a cada una de las funciones. La figura 3.2 muestra el resultado de ejecutar este mismo programa bajo Windows 95 después de ser recompilado con la versión de 16 bits de Delphi. Comparando la figura 3.1 con la figura 3.2, puede ver la diferencia entre tipos de entero de 16 bits y 32 bits.

Figure 3.2: La salida de la versión de 16 bits del programa Range, mostrando información sobre enteros, nuevamente.

El tamaño del tipo Integer varía dependiendo de la CPU y el sistema operativo utilizados. En versiones Windows de 16 bits, una variable entera ocupa dos bytes. En versiones de Windows de 32 bits, un Integer ocupa 4 bytes. Por esta razón, cuando usted recompila el programa Range, obtiene una salida distinta en cada caso.

Las dos representaciones distintas del tipo Integer no son un problema, siempre que su programa no asuma nada sobre el tamaño de los enteros. Si alguna vez guarda un Integer en un archivo utilizando una versión y lo carga con otra, tendrá algunos problemas. En esta situación, debería elegir un tipo de datos independiente de la plataforma (como LongInt o SmallInt). Para cálculos matemáticos o código genérico, la mejor elección es seguir la representación de enteros de la plataforma en que se quiera trabajar -- esto es, utilice el tipo Integer -- porque esto es lo que más le gusta a la CPU. El tipo Integer debería ser su primera elección cuando maneje números enteros. Use una representación distinta sólo si hay una razón imperiosa para hacerlo.

Rutinas de tipo ordinal

Hay algunas rutinas del sistema (rutinas definidas en el lenguaje Pascal y la unidad de sistema de Delphi) que funcionan en tipos ordinales. Se muestran en la tabla 3.2. Los programadores en C++ no deben olvidar de que las dos versiones del procedimiento Inc, con uno o dos parámetros, corresponden a los operadores ++ y += (y lo mismo para el procedimiento Dec).

Table 3.2: Rutinas del sistema para tipos ordinales

Rutina 

Finalidad 

Dec Decrementa la variable pasada como parámetro, en una unidad o por el valor del parámetro segundo, opcional.
Inc Incrementa la variable pasada como parámetro, en una unidad o por el valor especificado.
Odd Devuelve True si el argumento es un número par.
Pred Devuelve el valor precedente al argumento según el orden determinado por el tipo de datos.
Succ Devuelve el valor siguiente (successor) al argumento según el orden determinado.
Ord Devuelve un número, indicando el orden del argumento dentro del conjunto de valores del tipo de datos.
Low Devuelve el menor valor en el rango del tipo ordinal pasado como parámetro.
High Devuelve el menor valor en el rango del tipo ordinal.

Observe que algunas de estas rutinas, cuando se aplican a constantes, son evaluadas automáticamente por el compilados y reemplazadas por su valor. Por ejemplo, si hace una llamada a la función High(X), donde X se define como Integer, el compilador puede reemplazar la expresión con el valor más alto posible en el tipo de datos Integer.

Tipos reales

Los tipos reales representan números de coma flotante en varios formatos. El menor tamaño de almacenamiento corresponde a los números Single, implementados con un valor de 4 bytes. Aparte hay números de coma flotante Double, implemententados con 8 bytes, y números Extended, implementados con 10 bytes. Todos estos son tipos de datos de coma flotante de distinta precisión, que corresponden a las representaciones normalizadas IEEE, y son compatibles directamente por el coprocesador numérico de la CPU, lo que permite una velocidad máxima.

En Delphi 2 y Delphi 3 el tipo Real tenía la misma definición que en la versión de 16 bits; era un tipo de 48 bits. Pero su uso fue reprobado por Borland, que sugirió que se usasen los tipos Single, Double y Extended, en vez de aquel. Las razón era que el viejo formato de 6 bits no era compatible ni con las CPUs de Intel ni estaba entre los tipos reales oficiales IEEE. Para superar el problema totalmente, Delphi 4 modifica la definición del tipo Real para representar un número de coma flotante normalizado de 8 bytes (64 bits).

Además de la ventaja de usar una definición normalizada, este cambio permite a los componentes publicar propiedades basadas e el tipo Real, algo que Delphi 3 no permitía. Entre las desventajas podría haber problemas de compatibilidad. De ser necesario, puede evitar la eventual incompatibilidad utilizando la definición del tipo de Delphi 2 o 3; haga esto usando la siguiente opción de compilación :

{$REALCOMPATIBILITY ON}

Hay también dos tipos de datos extraños: Comp describe enteros muy grandes que usan 8 bytes (que pueden contener números de hasta 18 dígitos decimales); y Currency (no disponible en el Delphi de 16 bits) indica un valor decimal de coma fija con cuatro dígitos decimales, y la misma representación en 64 bits que el tipo Comp. Como implica el nombre, el tipo de datos Currency ha sido añadido para manejar valores monetarios muy precisos, con cuatro cifras decimales.

No podemos crear un programa similar el ejemplo Range de arriba con tipos de datos reales, porque no podemos usar las funciones High y Low o la función Ord en variables reales. Los tipos reales representan (en teoría) un conjunto de números infinito; los tipos ordinales representan un conjunto fijo de valores.

Nota: Déjeme explicar esto mejor. Cuando tiene el entero 23, puede determinar cuál es el valor siguiente. Los enteros son finitos (tienen un rango determinado y tienen un orden). Los números de coma flotante son infinitos incluso dentro de un pequeño, y no tienen orden : de hecho, ¿cuántos valores hay entre 23 y 24? Y ¿qué número sigue al 23.46? Es 23.47, 23.461 o 23.4601 ? ¡Es difícil decidirlo!

Por esta razón, tiene sentido pedir la posición ordinal del carácter 'w' en el rango del tipo de datos Char, pero no tiene ningún sentido preguntar por lo mismo acerca de 7143,1562 [aquí la coma es decimal] en el rango de un tipo de datos de coma flotante. Aunque, de hecho, puede usted saber si un número real tiene un valor superior a otro, no tiene sentido preguntar cuántos números reales existen antes de uno dado (este es el significado de la función Ord).

Los tipos reales juegan un papel pequeño en la parte del código dedicada a la interfaz de usuario (parte dedicada a Windows), pero son perfectamente implementables en Delphi, incluida la parte que toca a las bases de datos. La compatibilidad con tipos de coma flotante de la norma IEEE hace al lenguaje de programación Object Pascal muy apropiado para el amplio abanico de programas que requieren cálculos numéricos. Si está usted interesado en este aspecto, puede buscar las funciones aritméticas incorporadas a Delphi en la unidad de sistema (véase la ayuda de Delphi para más detalles).

Nota: Delphi también tiene una unidad Math que define rutinas matemáticas avanzadas, que cubren las funciones trigonométricas (como la función ArcCosh), finanzas (como la función InterestPayment) y estadística (como el procedimiento MeanAndStdDev). Hay muchas rutinas así, algunas de las cuales suenan bastante raras, como el procedimiento MomentSkewKurtosis (le dejo como ejercicio averiguar de qué se trata ...).

Fecha y Hora

Delphi usa tipos reales también para manejar información sobre la fecha y la hora. Para ser más precisos, Delphi define un tipo de datos específico, TDateTime. Este es un tipo de coma flotante, porque el tipo tiene que ser lo bastante amplio para almacenar ños, meses, días, horas, minutos y segundos, hasta resolución de milisegundos, en una sola variable. Las fechas se almacenan como número de días desde el 30 de diciembre de 1899 (12/30/1899), donde los valores negativos indican fechas anteriores al año 1899, en la parte entera del valor de TDateTime. La hora se almacena como fracciones de un días en la parte decimal del valor.

TDateTime no es un tipo predefinido que el compilador comprende, sino que es definido en la unidad de sistema como :

type
  TDateTime = type Double;

Usar el tipo TDateTime es bastante fácil, porque Delphi incluye varias funciones que operan sobre este tipo. Puede encontrar una lista de estas funciones en la tabla 3.3.

Tabla 3.3: Rutinas del sistema para el tipo TDateTime

Rutina 

Descripción 

Now Devuelve la fecha y la hora actual en un solo valor TDateTime.
Date Devuelve sólo la fecha actual.
Time Devuelve sólo la hora actual.
DateTimeToStr Convierte un valor de fecha y hora en una cadena, utilizando formato por defecto; para tener mayor control sobre la conversión, utilice la función FormatDateTime.
DateTimeToString Copia el valor de fecha y hora en un buffer (tampón) de cadena, en formato por defecto.
DateToStr Convierte la porción de fecha de un valor TDateTime en una cadena.
TimeToStr Convierte la porción de hora de un valor TDateTime en una cadena.
FormatDateTime Da un formato especificado a fecha y hora; puede especificar qué valores quiere ver y qué formato utilizar, proveyendo una cadena de formato complejo.
StrToDateTime Convierte una cadena con información de fecha y hora en un valor TDateTime, provocando una excepción en caso de error en el formato de la cadena.
StrToDate Convierte una cadena con información de fecha en un valor TDateTime.
StrToTime Convierte una cadena con información de hora en un valor TDateTime
DayOfWeek Extrae el número correspondiente al día de la semana del valor TDateTime que se pasa como parámetro.
DecodeDate Estrae los valores de año, mes y día de un valor de fecha.
DecodeTime Extrae los valores de un valor de hora.
EncodeDate Convierte valores de año, mes y día en un valor TDateTime.
EncodeTime Convierte valores de hora, minuto, segundo y milisegundo en un valor TDateTime.

Para mostrarle cómo usar este tipo de datos y algunas de las rutinas relacionadas con él, he construido un ejemplo sencillo, llamado TimeNow. El formulario principal de este ejemplo tiene un componente de botón (Button) y de lista (ListBox). Cuando el programa se inicia, se calcula y muestra la fecha y hora actual, automáticamente. Cada vez que se pulsa el botón, el programa muestra el tiempo pasado desde que el programa comenzó.

Este es el código relacionado con el evento OnCreate del formulario :

procedure TFormTimeNow.FormCreate(Sender: TObject);
begin
  StartTime := Now;
  ListBox1.Items.Add (TimeToStr (StartTime));
  ListBox1.Items.Add (DateToStr (StartTime));
  ListBox1.Items.Add ('Pulse botón para ver el tiempo transcurrido');
end;

La primera instrucción es una llamada a la función Now, que devuelve la fecha y hora actuales. Este valor se almacena en la variable StartTime, declarada como variable global, como sigue :

var
  FormTimeNow: TFormTimeNow;
  StartTime: TDateTime;

He añadido sólo la segunda declaración, ya que la primera viene dada por Delphi. Por defecto, es la siguiente :

var
  Form1: TForm1;

Al cambiar el nombre del formulario, esta declaración se actualiza automáticamente. Utilizando variables globales no es realmente el mejor enfoque : sería mejor utilizar un campo privado de la clase del formulario, un asunto relacionado con la programación orientada a objetos y discutido en Mastering Delphi 4 [publ. en español como Delphi 4].

Las siguientes tres instrucciones añaden tres entradas al componente ListBox a la izquierda del formulario, con el resultado que se ve en la figura 3.3. La primera línea contiene la porción de tiempo del valor TDateTime convertido en una cadena, el segundo la porción de la fecha, del mismo valor. Al final, el código añade un simple mensaje recordatorio.

Figura 3.3: La salida del programa de ejemplo TimeNow al iniciarse.

Esta tercera cadena es reemplazada por el programa cuando el usuario pincha en el botón Elapsed :

procedure TFormTimeNow.ButtonElapsedClick(Sender: TObject);
var
  StopTime: TDateTime;
begin
  StopTime := Now;
  ListBox1.Items [2] :=  FormatDateTime ('hh:nn:ss',
    StopTime - StartTime);
end;

Este código extrae la hora nueva y calcula la diferencia con el valor de hora almacenado cuando el programa se inició. Ya que necesitamos utilizar un valor que calculamos en un gestor de eventos distinto, tuvimos que almacenarlo en una variable global. De hecho, hay mejores alternativas, basadas en clases.

Nota: El código que reemplaza el valor acutal de la tercera cadena, utiliza el índice 2. La razón es que las entradas de la lista ListBox se cuentan desde cero : la primera es la número 0, la segunda la número 1, y la tercera la número 2. Comentaremos más sobre esto cuando hablemos de matrices.

Aparte de hacer una llamada a TimeToStr y DateToStr, puede utilizar la función FormatDateTime, más potente, como lo he hecho en el último método, arriba (véase la ayuda de Delphi para saber cómo se da formato a los parámetros). Tenga también en cuenta que los valores de hora y fecha se transforman en cadenas, dependiendo de la configuración regional de su sistema Windows. Delphi lee estos valores del sistema, y los copias a una serie de constantes globales declaradas en la unidad SysUtils. Algunas de ellas son :

DateSeparator: Char;
ShortDateFormat: string;
LongDateFormat: string;
TimeSeparator: Char;
TimeAMString: string;
TimePMString: string;
ShortTimeFormat: string;
LongTimeFormat: string;
ShortMonthNames: array [1..12] of string;
LongMonthNames: array [1..12] of string;
ShortDayNames: array [1..7] of string;
LongDayNames: array [1..7] of string;

Otras constantes globales están relacionadas al formato de moneda y de números de coma flotante (coma decimal española contra punto decimal inglés). Puede encontrar la lista completa en el archivo de ayuda de Delphi bajo el título Currency and date/time formatting variables.

Nota: Delphi incluye un componente DateTimePicker, que prové un modo sofisticado de entrar una fecha, seleccionándola de un calendario.

Tipos específicos de Windows

Los tipos de datos predefinidos que hemos visto hasta ahora son parte del lenguaje Pascal. Delphi también incluye otros tipos de datos definidos por Windows. Estos tipos de datos no son parte integrante del lenguaje, pero son parte de las bibliotecas de Windows. Entre los tipos de Windows hay nuevos tipos por defecto (como DWord o UInt), muchos registros (o estructuras), varios tipos de puntero (pointer), etcétera.

De los tipos de datos de Windows, el más importante se representa con handles, que se comentan en el capítulo 9.

Typecasting y conversión entre tipos

Como hemos visto, no puede asignar una variable a otra de un tipo diferente. En caso de que necesite hacerlo, hay dos opciones. La primera es el typecasting (moldeado de tipos), que usa una notación funcional simple, con el nombre del tipo de dato de destino :

var
  N: Integer;
  C: Char;
  B: Boolean;
begin
  N := Integer ('X');
  C := Char (N);
  B := Boolean (0);

Puede usted moldear de un tipo de datos a otro del mismo tamaño. Normalmente es seguro moldear entre tipos ordinales, pero también puede moldear entre tipos de puntero (y también objetos), siempre que sepa qué está haciendo.

De cualquier modo, moldear suele ser una práctica de programación peligrosa, ya que le permite acceder a un valor como si representase otra cosa. Como las representaciones internas de tipos de datos no suelen encajar, se expone a errores difíciles de detectar. Por esta razón, lo mejor es evitar el moldeado de tipos.

La segunda opción es usar una rutina de conversión entre tipos. Las rutinas para los distintos tipos de conversiones vienen resumidas en la tabla 3.4. Algunas de estas rutinas funcionan sobre los tipos de datos que discutiremos en las siguientes secciones. Tenga en cuenta que la tabla no incluye rutinas para tipos especiales (como TDateTime o una variante) o rutinas destinadas especificamente al formateo, como las potentes rutinas Format y FormatFloat.

Tabla 3.4: Rutinas del sistema para la conversión entre tipos

Rutina 

Descripción 

Chr Convierte un número ordinal en un carácter ANSI.
Ord Convierte un valor de tipo ordinal en el número que indica su orden.
Round Convierte un valor de tipo real en un número de tipo entero, redondeando su valor.
Trunc Convierte un valor de tipo real en un número de tipo entero, truncando su valor.
Int Extrae la parte entera del argumento de valor en coma flotante.
IntToStr Convierte un número en una cadena.
IntToHex Convierte un número en una cadena con su representación hexadecimal.
StrToInt Convierte una cadena en un número, provocando una exception si la cadena no representa un entero válido.
StrToIntDef Convierte una cadena en un número, usando un valor por defecto si la cadena no es correcta.
Val Convierte una cadena en un número (rutina tomada de Turbo Pascal, disponible por compatibilidad).
Str Convierte un número en una cadena, usando parámetros de formateo (rutina tomada de Turbo Pascal, disponible por compatibilidad).
StrPas Convierte una cadena de terminación nula (null-terminated) en una cadena de tipo Pascal. Esta conversión se realiza automáticamente sobre cadenas AnsiStrings en Delphi de 32 bits. (Véase la sección dedicada a las cadenas, más adelante en este mismo capítulo.)
StrPCopy Copia una cadena tipo Pascal en una cadena de terminación nula. Esta conversión se hace con un simple simple moldeo (typecast) sobre0 PChar, en Delphi de 32 bits. (Véase la sección dedicada a las cadenas, más adelante en este mismo capítulo.)
StrPLCopy Copia una porción de una cadena tipo Pascal en una cadena de terminación nula.
FloatToDecimal Convierte un valor de coma flotante a un registro, incluyendo su representación decimal (exponentes, dígitos, signo).
FloatToStr Convierte un valor de coma flotante a su representación como cadena, con formato por defecto.
FloatToStrF Convierte un valor de coma flotante a su representación como cadena, con el formato especificado.
FloatToText Copia un valor de coma flotante a un buffer (tampón) de cadena, con el formato especificado.
FloatToTextFmt Como la rutina anterior, copia un un valor de coma flotante a un buffer (tampón) de cadena, con el formato especificado.
StrToFloat Convierte una cadena Pascal a un valor de coma flotante.
TextToFloat Convierte una cadena de terminación nula a un valor de coma flotante.

Conclusión

En este capítulo hemos explorado la noción básica de tipo en Pascal. Pero el lenguaje tiene otra cualidad muy importante : permite a los programadores definir nuevos tipos de datos personalizados, llamados tipos de datos definidos por el usuario. Este es el asunto de que trata el siguiente capítulo.


Capítulo siguiente: Tipos de datos definidos por el usuario


© Copyright Marco Cantù, Wintech Italia Srl 1995-99
© Copyright de la traducción, Rafael Barranco-Droege, 2000