2011-09-29 4 views
5

He encontrado la directiva de preprocesador #define antes mientras aprendía C, y luego también la encontré en algún código que leí. Pero aparte de usarlo para sustituir definitivamente las constantes y para definir macros, no he entendido realmente el caso especial donde se usa sin un "cuerpo" o cadena de tokens.¿Qué casos de uso necesitan #define sin una cadena de tokens?

Tomemos por ejemplo esta línea:

#define OCSTR(X) 

Al igual que! ¿Cuál podría ser el uso de esto o mejor? ¿Cuándo es necesario este uso de #define?

+0

Esto puede ser útil en conjunción con otro conjunto de directivas que permiten la compilación condicional. Un #define sin una cadena de token elimina las apariciones de identificador del archivo de origen. El identificador permanece definido y puede ser probado usando las directivas #if defined y #ifdef. – AminM

Respuesta

6

Esto se utiliza en dos casos. La primera y más frecuente implica compilación condicional:

#ifndef XYZ 
#define XYZ 
// ... 
#endif 

que ha utilizado con seguridad usted mismo para incluir a los guardias, pero también puede ser utilizado para cosas como las dependencias del sistema:

#ifdef WIN32 
// Windows specific code here... 
#endif 

(En en este caso, WIN32 probablemente se define en la línea de comandos, pero también se puede definir en un archivo "config.hpp"). Normalmente, esto solo implica macros similares a objetos (sin una lista de argumentos o paréntesis) .

El segundo sería el resultado de la compilación condicional.Algo como:

#ifdef DEBUG 
#define TEST(X) text(X) 
#else 
#define TEST(X) 
#endif 

que permite escribir cosas como:

TEST(X); 

que se llame a la función si se ha definido DEBUG, y no hacer nada si no es .

+0

Aceptado esto no porque otros no sean correctos, sino porque agrega más aclaración a la respuesta correcta. Gracias – nemesisfixx

3

Tal macro suele aparecer en par y en el interior condicional #ifdef como:

#ifdef _DEBUG 
    #define OCSTR(X) 
#else 
    #define OCSTR(X) SOME_TOKENS_HERE 
#endif 

Otro ejemplo,

#ifdef __cplusplus 
    #define NAMESPACE_BEGIN(X) namespace X { 
    #define NAMESPACE_END } 
#else 
    #define NAMESPACE_BEGIN(X) 
    #define NAMESPACE_END 
#endif 
0

Esto puede utilizarse cuando es posible que desee silenciosa alguna función. Por ejemplo, en el modo de depuración que desea imprimir algunas sentencias de depuración y en el código de producción que desea omitir ellos:

#ifdef DEBUG 
#define PRINT(X) printf("%s", X) 
#else 
#define PRINT(X) // <----- silently removed 
#endif 

Uso:

void foo() 
{ 
    PRINT("foo() starts\n"); 
    ... 
} 
+0

Su respuesta (y la de muchos otros) es verdadera, pero su ejemplo es peligroso. ¿Qué pasa si hay un if() sin encierre {} presente antes de la IMPRESIÓN (X)? Para los lectores: cuidado, este es solo un ejemplo simple para no ser usado tal como es. – Offirmo

+0

Esa es la razón por la cual en C/C++ cada macro debe ser una expresión solo para evitar ese tipo de escenarios. Saludos. – BigMike

0

#define macros son simplemente reemplazados, literalmente, por su texto de reemplazo durante el preprocesamiento. Si no hay texto de reemplazo, entonces ... ¡no son reemplazados por nada! Por lo que este código fuente:

#define FOO(x) 

print(FOO(hello world)); 

será pre-procesada en esto:

print(); 

Esto puede ser útil para deshacerse de cosas que no desea, como, por ejemplo, assert(). Es principalmente útil en situaciones condicionales, donde bajo algunas condiciones hay un cuerpo no vacío, sin embargo.

0

Como puede ver en las respuestas anteriores, puede ser útil al depurar su código.

#ifdef DEBUG 
#define debug(msg) fputs(__FILE__ ":" (__LINE__) " - " msg, stderr) 
#else 
#define debug(msg) 
#endif 

lo tanto, cuando se está depurando, la función imprimirá el número de línea y el nombre del archivo para saber si hay un error. Y si no está depurando, simplemente no producirá salida

0

Hay muchos usos para tal cosa.

Por ejemplo, una es para que la macro tenga un comportamiento diferente en las compilaciones diferentes. Por ejemplo, si desea que los mensajes de depuración, podría tener algo como esto:

#ifdef _DEBUG 
    #define DEBUG_LOG(X, ...) however_you_want_to_print_it 
#else 
    #define DEBUG_LOG(X, ...) // nothing 
#endif 

Otro uso podría ser para personalizar el archivo de cabecera basa en su sistema. Esto es de mi cabecera OpenGL implementado-mesa en Linux:

#if !defined(OPENSTEP) && (defined(__WIN32__) && !defined(__CYGWIN__)) 
# if defined(__MINGW32__) && defined(GL_NO_STDCALL) || defined(UNDER_CE) /* The generated DLLs by MingW with STDCALL are not compatible with the ones done by Microsoft's compilers */ 
# define GLAPIENTRY 
# else 
# define GLAPIENTRY __stdcall 
# endif 
#elif defined(__CYGWIN__) && defined(USE_OPENGL32) /* use native windows opengl32 */ 
# define GLAPIENTRY __stdcall 
#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 303 
# define GLAPIENTRY 
#endif /* WIN32 && !CYGWIN */ 

#ifndef GLAPIENTRY 
#define GLAPIENTRY 
#endif 

y se utiliza en las declaraciones de cabecera como:

GLAPI void GLAPIENTRY glClearIndex(GLfloat c); 

GLAPI void GLAPIENTRY glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); 

GLAPI void GLAPIENTRY glClear(GLbitfield mask); 

... 

(I eliminado la parte de GLAPI)

Así se obtiene la imagen , una macro que se usa en algunos casos y no se usa en otros casos podría definirse como algo en esos casos y nada en esos otros casos.

Otros casos podría ser la siguiente:

Si la macro no toma parámetros, que podría ser sólo para declarar algún caso. Un ejemplo famoso es proteger los archivos de encabezado. Otro ejemplo sería algo como esto

#define USING_SOME_LIB 

y más tarde podría ser utilizado como esto:

#ifdef USING_SOME_LIB 
... 
#else 
... 
#endif 

Podría ser que la macro se utilizó en algún momento de hacer algo (por ejemplo, registro), pero luego en el lanzamiento, el propietario decidió que el registro ya no es útil y simplemente eliminó el contenido de la macro para que quede vacío. Sin embargo, esto no es recomendable, use el método que mencioné al principio de la respuesta.

Por último, podría estar allí sólo para una explicación más detallada, por ejemplo, se puede decir

#define DONT_CALL_IF_LIB_NOT_INITIALIZED 

y escribir funciones como:

void init(void); 
void do_something(int x) DONT_CALL_IF_LIB_NOT_INITIALIZED; 

Aunque este último caso es un poco absurdo, pero tendría sentido en tal caso:

#define IN 
#define OUT 

void function(IN char *a, OUT char *b); 
2

Un caso raro que recientemente desenterré para responder una questi resultó ser simplemente un comentario en la naturaleza. El código en cuestión parecía:

void CLASS functionName(){ 
    // 
    // 
    // 
} 

descubrí que era sólo un vacío #define, que el autor había elegido para documentar que la función de acceso a las variables globales en el proyecto:

C++ syntax: void CLASS functionName()?

Así realmente no tan diferente de si dijera /* CLASS */, excepto que no permite errores tipográficos como /* CLAAS */ ... algunos otros pequeños beneficios quizás (?)

0

Estoy de acuerdo con cada respuesta , pero me gustaría señalar algo pequeño y trivial.

Al ser un purista C He crecido con la afirmación de que todos y cada #define debe ser una expresión, por lo que, incluso si se trata de una práctica común usando:

#define WHATEVER 

y probarlo con

#ifdef WHATEVER 

Creo que es siempre mejor escribir:

#define WHATEVER (1) 

también #debug macros serán expresiones:

#define DEBUG (xxx) (whatever you want for debugging, value) 

De esta manera, usted está completamente a salvo de mal uso de #macros y evita problemas desagradables (especialmente en un proyecto de 10 millones de la línea C)

+0

Este debate '# if' vs' # ifdef' puede interesarle, me siento personalmente del lado de '# if' http://stackoverflow.com/questions/135069/ifdef-vs-if-which-is- mejor-seguro – HostileFork

+0

Me viene a la mente el uso efectivo de #if 0 para comentar piezas enteras de código: D. Por cierto, el debate es interesante. Como de costumbre, no hay una forma correcta o incorrecta de hacer las cosas, depende de lo que estés haciendo. Le daré una lectura CUANTO ANTES. Gracias. – BigMike

Cuestiones relacionadas