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__) |
__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: |
__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)
[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).