Disponible la nueva versión "donationware" 7.3 de OrganiZATOR
Descubre un nuevo concepto en el manejo de la información.
La mejor ayuda para sobrevivir en la moderna jungla de datos la tienes aquí.

Curso C++

[Home]  [Inicio]  [Índice]


1.4.1a  Constantes manifiestas

§1  Sinopsis

Los compiladores C++ utilizan una serie de constantes (generalmente números enteros) que, como puede comprobarse en los ejemplos que siguen, se utilizan para albergar información muy diversa.  La mayoría de las veces son globales, aunque no necesariamente, y son conocidas como constantes manifiestas o simbólicas.

La razón del nombre es que están referenciadas en el fuente mediante etiquetas (nombres) que en realidad son macros definidas en alguno de los múltiples ficheros de cabecera que acompañan al compilador (el programador no tiene que hacer nada al respecto para definirlas).  Posteriormente, en la fase de preproceso, estas etiquetas son sustituidas por el valor correspondiente.  Por ejemplo, MS VC++ puede incluir en el fuente el identificativo ID_FILE_PRINT_PREVIEW. Posteriormente esta constante simbólica será transformada en el valor numérico 57609 por el preprocesador.

La razón de utilizar estas etiquetas en vez de los valores numéricos correspondientes, es doble: por una parte son más fáciles de recordar por el programador que los utiliza. Por otra, permite que los valores concretos puedan ser cambiados de una revisión a otra del compilador, simplemente cambiando los "defines" ( 4.9.10b), sin necesidad de tocar los fuentes de las aplicaciones.

Nota:  además de estas constantes, los compiladores también utilizan una serie de variables y tipos globales de nombres predefinidos que son incluidos automáticamente en cualquier programa C++ para usos varios, como fechas, horas, etc. ( 4.1.3a).

§2  Utilización

Las constantes manifiestas se suelen utilizar para definir determinados comportamientos o situaciones, bien en forma aislada o en expresiones compuestas.  Por ejemplo, una herramienta para construir aplicaciones gráficas bajo Windows informa que para crear una ventana debe instanciarse un objeto de la clase _Frame (una superclase definida en dicho entorno) cuyo constructor acepta una serie de argumentos que definen las características de la nueva ventana.  Entre ellos un long denominado style, define si la ventana será redimensionable; si podrá minimizarse y maximizarse; si tendrá un icono distintivo, etc.  El constructor tiene el siguiente aspecto (hemos eliminado el resto de argumentos por simplicidad)

_Frame (..., long style = _DEFAULT_FRAME_STYLE, ... ) { ... }


Como puede verse, el estilo tiene un valor por defecto (que será utilizado por el sistema si el programador no proporciona uno específico) definido mediante una constante manifiesta cuyo valor no nos importa demasiado, dado que su nombre es bastante significativo. Por otro lado, el manual nos señala que los valores permitidos son los siguientes:

_DEFAULT_FRAME_STYLE = _MINIMIZE_BOX | _MAXIMIZE_BOX | _RESIZE_BOX | _SYSTEM_MENU | _CAPTION;

// _ICONIZE               Display the frame iconized (minimized)
// _CAPTION               Puts a caption on the frame
// _MINIMIZE_BOX          Displays a minimize box on the frame
// _MAXIMIZE              Displays the frame maximized
// _MAXIMIZE_BOX          Displays a maximize box on the frame
// _STAY_ON_TOP           Stay on top of other windows
// _SYSTEM_MENU           Displays a system menu
// _SIMPLE_BORDER         Displays no border or decorations
// _RESIZE_BORDER         Displays a resizeable border around the window
// _FRAME_FLOAT_ON_PARENT Causes the frame to be above the parent window in the z-order
// _FRAME_TOOL_WINDOW     Causes a frame with a small titlebar


Teniendo en cuenta que | es el operador OR inclusivo de manejo de bits ( 4.9.3), puede comprobar el lector como la utilización de  estas constantes permite establecer fácilmente y sin mayor explicación, el valor correspondiente a cualquiera de los comportamientos posibles para la ventana que deseamos crear.

§3  Constantes simbólicas del C++ Estándar

El Estándar C++ establece que los compiladores definirán las siguientes constantes simbólicas [2]:

Constante Significado
__cplusplus Cuando se compila una unidad de compilación C++ este valor debe estar definido como 199711L (un long).  El Estándar establece que en sucesivas versiones se adoptarán valores mayores, y que los compiladores no estándar deben adoptar un valor de cinco cifras decimales como máximo.
__DATE__ Esta constante contendrá una cadena literal con la fecha de compilación del fuente en la forma "Mmm dd yyyy" (mes, día, año), donde los nombres de los meses son los que se obtienen con la función de librería asctime( 5.5.1), y el primer carácter del día es un espacio si el valor es menor que 10.  En caso que la fecha de compilación no esté disponible, el valor de esta constante dependerá de la implementación.
__FILE__ Constante literal que contiene el nombre (presumible) del fichero que se está ejecutando.
__LINE__ Constante decimal que indica el número de línea del fuente que se está ejecutando.
__STDC__ Cuando y con que valor se definirá esta constante depende de la implementación.
__TIME__ La hora de compilación del fuente en forma de una cadena literal "hh:mm:ss" con el formato proporcionado por la función de librería asctime().  En caso que la hora de compilación no esté disponible este valor dependerá de la implementación.

Como puede verse, excepto para __LINE__ y __FILE__, el resto de valores permanece constante a lo largo de toda la unidad de compilación.  A su vez los valores de  __LINE__ y __FILE__ pueden ser establecidos mediante la directiva #line de preproceso ( 4.9.10h), aunque no pueden ser redefinidos o indefinidos ().

§4  Constantes simbólicas del compilador Borland C++ 5.5

El Estándar establece que los compiladores son libres de definir macros adicionales mediante directivas #define, y que estos valore puedan ser redefinidos o indefinidos mediante las directivas correspondientes.  En concreto, el compilador Borland C++ 5.5 utiliza las siguientes: 

Constante Valor Descripción
__BCOPT 1 Definido en cualquier compilador que tenga optimización.
__BCPLUSPLUS__ 0x0550 Si se ha adoptado compilación C++ (C++Builder puede compilar también como C estándar).
__BORLANDC__ 0x0550 Número de versión del compilador (en el momento de redactar estos apuntes). Otros compiladores utilizan otras constantes, de forma que es posible detectar en tiempo de compilación qué compilador se está utilizando, lo que es útil cuando se redactan aplicaciones multi-plataforma que requieren ciertas adaptaciones puntuales en función del compilador utilizado en cada momento.  A continuación se muestra un trozo de código tomado de un caso real en el que puede apreciarse los valores utilizados y el tipo de uso de estas constantes.

 

#if !defined(__CYGWIN__) && defined(__unix__)
   /* ... */
#elif defined(__CYGWIN__) || \
    (defined(_WIN32) && defined(WINVER) && WINVER >= 0x0500)
   /* ... */
#else
   /* ... */
#endif

#if !defined(__BORLANDC__) || __BORLANDC__ > 0x551
  /* ... */
#endif
#if defined(__GNUC__) && __GNUC__ >= 3
   /* ... */
#endif

__CDECL__ 1 Este valor es el indicado solo si se ha establecido que la convención de llamada es cdecl; ( 4.4.6a) en otro caso es indefinido.
_CHAR_UNSIGNED 1 Por defecto indica que el tipo char es unsigned char ( 2.2.1)  La opción de compilación -K indefine esta macro.
 __CODEGUARD__ Este valor está definido solo si se utiliza alguna de las opciones CodeGuard del compilador.
__CONSOLE__ Cuando está definida, esta macro indica que el programa es una aplicación de consola.
_CPPUNWIND 1 Este valor permite "stack unwinding" ( 1.6); por defecto la opción está activada; para desactivarla hay que utilizar la opción -xd- del compilador.
__cplusplus 1 Definido solo si está en modo C++.
__DATE__ cadena literal Contiene la fecha en que el proceso empezó en el fichero actual.
__DLL__ 1 Definido solo si se ha utilizado la opción -WD del compilador (generar un .DLL ejecutable [1]; lo mismo que la opción -tWD).
__FILE__ cadena literal Nombre del fichero que se está ejecutando.
__FLAT__ 1 Definido solo si se ha compilado para el modelo de uso de memoria "plano" de 32-bit (32-bit flat memory model).
__FUNC__ cadena literal Nombre de la función que se está ejecutando actualmente (ver ejemplo ).

Nota: el estándar C99 utiliza la constante __func__. Además del anterior el compilador GNU g++ también reconoce el identificador __FUNCTION__ para este menester, aunque se recomienda utilizar el primero. Este compilador también utiliza la constante __PRETTY_FUNCTION__, que proporciona la declaración (signature) de la función.  Por ejemplo, siendo el método foo de una clase C definido como:

int foo (int x) { return x*x }

el identificador __FUNCTION__ contiene C::foo, mientras que __PRETTY_FUNCTION__ contiene void C::foo(int)

__LINE__ decimal Número de línea del fichero fuente que se está ejecutando.
_M_IX86 1 El valor por defecto es 300 (código compatible con el procesador 80386), pero puede cambiarse a los valores 400 o 500 mediante la opción /4 o /5 del compilador ( 1.4.3).
__MSDOS__ 1 Constante entera.
__MT__ 1 Definido solo si se ha utilizado la opción -tWM del compilador; indica que se generará código 32-bit multi-hebra (igual que -WM)
__PASCAL__ 1 Definido solo si se utiliza la convención Pascal de llamada ( 4.4.6a)
__STDC__ 1 Definido solo si de ha utilizado la opción -A del compilador (utilizar las palabras clave y extensiones ANSI)
__TCPLUSPLUS__ 0x0550 Número de versión
__TEMPLATES__ 1 Significa que se soportan los "templates" ( 4.12)
__TIME__ cadena literal Indica el instante de comienzo de ejecución del fichero actual.
__TLS__ 1 Almacenamiento local para las habras de ejecución (siempre 1 en C++Builder)
__TURBOC__ 0x0550 Versión actual. Puede ser modificado en futuras versiones del compilador.
_WCHAR_T 1 Definido solo para programas C++ (C++Builder puede compilar también como C); sirve para indicar que wchar_t es un tipo definido intrínsecamente ( 2.2.1a1)
_WCHAR_T_DEFINED 1 Igual que el anterior.
_Windows Definido para código exclusivamente Windows
__WIN32__ 1 Definido para aplicaciones de interfaz gráfica y de consola.


Nota: __DATE____FILE____ FUNC____LINE____STDC__ y __TIME__ no pueden ser redefinidas o indefinidas ( #undef).

Por su parte, __DATE____FILE____ LINE____STDC____TIME__ y __TIMESTAMP__ son constantes manifiestas del Estándar ANSI C, por lo que es frecuente que estén presentes también en los compiladores C++ (están presentes en el compilador MS Visual C++ 6.0, aunque la última, que proporciona la fecha y hora de la última modificación del fuente actual en forma de cadena literal, no está definida en el compilador de Borland).

Ejemplo  de utilización de la constante manifiesta __FUNC__

#include <stdio.h>

int main() {
  printf("Esta ejecutando la funcion %s\n", __FUNC__);
  return 0;
}

Salida:

Esta ejecutando la funcion main

La constante manifiesta __FUNC__ también puede ser utilizada en funciones miembro:

#include <iostream.h>
class UNAclase  {
  public:
  void UNmetodo(void)  {
    cout << "Esta ejecutando el metodo: " << __FUNC__ << endl;
  }
};

int main()  {
  UNAclase unaclase;
  unaclase.UNmetodo();
  return 0;
}

Salida:

Esta ejecutando el metodo: UNAclase::UNmetodo

Hay que advertir que esta constante manifiesta no es válida si se declara en un ámbito global.  Tal como se indica en el ejemplo que sigue, si se utiliza fuera del ámbito de una función, __FUNC__ puede tener un valor indeterminado (basura):

#include <stdio.h>
char * funcStr = __FUNC__;
int main() {
  printf("Esta en la funcion %s\n", funcStr); // No funciona correctamente!
  return 0;
}

Información adicional:    The __func__ Predeclared Identifier is Coming to C++


  Ver ejemplos adicionales con __FILE__ y __LINE__:  ( 1.4.5)

  Inicio.


[1]  El compilador C++ Builder, como la mayoría de los compiladores para Windows, es capaz de generar un ejecutable .EXE o un fichero ejecutable especial, "de enlace dinámico" .DLL (Dynamic Linked Library 5).  Este tipo de ejecutable se llama desde el programa principal, y contiene partes del programa (subrutinas) que son llamados desde varios sitios.  También suele utilizarse para albergar rutinas que pueden ser utilizadas por distintos ejecutables.

En realidad todos los servicios que ofrece Windows son accesibles mediante llamadas a estos DLLs que, como se ha indicado, se caracterizan porque no pueden ser llamados a ejecución como los .EXE normales, sino desde otro ejecutable y de una forma especial (se invocan como una llamada a función).

[2]  Es típico que los compiladores utilicen internamente nombres que comienzan con guión bajo. Por esta razón se recomienda abstenerse de usar identificadores que comiencen con guión bajo en nuestros programas ( 3.2.2).