2010-05-10 9 views
6

¿Cuál es el rol de la directiva #define?¿Cuál es el propósito de la directiva #define en C++?

+1

Consulte el código de ejemplo del siguiente artículo como un ejemplo de cómo * no * usar macros: http://stackoverflow.com/questions/2777774/a-out-termniated-garbage-output-due- to-smashing-of-stack-how-to-remove-this –

+1

@Nathan: Vayamos a la verdadera fuente SO de macros malas: http://stackoverflow.com/questions/652788/what-is-the-worst- mundo real-macros-pre-procesador-abuso-youve-ever-across. –

+0

Touche, @David, simplemente fui al más cercano que tenía en la memoria. Su enlace incluye una serie de atrocidades. –

Respuesta

15

#define se utiliza para crear macros en C y en C++. Puede leer más sobre esto en el C preprocessor documentation. La respuesta rápida es que hace algunas cosas:

  1. Macros simples: basta con solo reemplazar el texto. Tiempo de compilación constantes son un buen ejemplo:

    #define SOME_CONSTANT 12 
    

    simplemente reemplaza el texto SOME_CONSTANT con 12 siempre que aparece en el código. Este tipo de macro se usa a menudo para proporcionar una compilación condicional de bloques de código. Por ejemplo, podría haber una cabecera incluida por cada archivo fuente en un proyecto con una lista de opciones para el proyecto:

    #define OPTION_1 
    #define OPTION_2 
    #undef OPTION_3 
    

    Y luego los bloques de código en el proyecto se envuelven con juego #ifdef/#endif# bloques para permitir y deshabilitar esas opciones en el proyecto terminado. Usar el indicador -D gcc proporcionaría un comportamiento similar. Sin embargo, existen fuertes opiniones sobre si este método es realmente una buena forma de proporcionar una configuración para una aplicación.

  2. Macros con argumentos: le permite crear macros 'funcionales' que pueden tomar argumentos y manipularlos. Por ejemplo:

    #define SQUARE(x) ((x) * (x)) 
    

    devolvería el cuadrado del argumento como resultado; ¡tenga cuidado con posibles órdenes de operaciones o problemas de efectos secundarios! En el siguiente ejemplo:

    int x = SQUARE(3);  // becomes int x = ((3) * (3)); 
    

    voluntad funciona bien, pero algo como:

    int y = SQUARE(f()); // becomes int y = ((f()) * (f())); 
    

    llamarán f() dos veces, o lo que es peor:

    int z = SQUARE(x++); // becomes int z = ((x++) * (x++)); 
    

    resulta en un comportamiento indefinido!

    Con algunas herramientas, las macros con argumentos también pueden ser variadic, que pueden ser útiles.

Como se menciona a continuación en los comentarios, el uso excesivo de macros, o el desarrollo de macros excesivamente complicadas o confusas se considera mal estilo por muchos - como siempre, puso la legibilidad, mantenibilidad, y debuggability de su código de arriba " hábiles trucos técnicos.

+5

+1. Y dado que OP preguntó acerca del "papel" que desempeña '# define', debe enfatizarse que las macros no deben ser usadas en exceso. – stakx

+0

Las macros variables son estándar en C99, por lo que la mayoría de las herramientas modernas deberían ser compatibles. – pkh

+1

+1, pero debería agregar un ejemplo de cómo SQUARE() será * expandido * en algunas situaciones. – greyfade

7

#define (y es opuesto, #undef) se puede utilizar para establecer las directivas del compilador que luego se pueden probar contra el uso de #ifndef o #ifdef. Esto permite definir comportamientos personalizados dentro del archivo fuente. Se usa comúnmente para compilar para diferentes entornos o para depurar código.

Un ejemplo:

#define DEBUG 



#ifdef DEBUG 

//perform debug code 

#endif 
0

en C o C++ #define le permite crear macros del preprocesador.

En la normalidad C o C++ proceso de construcción de la primera cosa que sucede es que el preprocesador se ejecuta, el preprocesador se ve sin embargo la fuente de los archivos de directivas de preprocesador #define como o # include y luego se lleva a cabo operaciones simples con ellos.

En el caso de una directiva #define, el preprocesador realiza una simple sustitución basada en texto.

Por ejemplo, si tiene el código

#define PI 3.14159f 

float circum = diameter*PI; 

el preprocesador lo convertiría en:

float circum = diameter* 3.14159; 

simplemente reemplazando los casos de PI con el texto correspondiente. Esta es sólo la forma más simple de una declaración #define para usos más avanzados echa un vistazo a este article de MSDN

0

inCorrectUseOfHashDefine()

{

El papel de #define es desconcertar a las personas que heredan con su código de las declaraciones azul como:

foreverandever 

debido a:

#define foreverandever for(;;) 

}

favor favorecer constantes de más de # define.

También para establecer las directivas del compilador ...

+2

¿Por qué el -2? Es un punto válido y me atengo a él. –

+0

porque este * no * es el papel de un #define, sino un * uso indebido * del mismo. –

+0

@Rene OK - He hecho mis intenciones más explícitas –

1

La directiva #define tiene dos usos comunes.

El primero es controlar cómo actuará el compilador. Para hacer esto, también necesitamos #undef, #ifdef y #ifndef. (y #endif también ...)

Puede hacer "lógica de compilación" de esta manera. Un uso común es para activar o no una porción de depuración del código, al igual que:

#ifdef DEBUG 

//debug code here 

#endif 

y que sería capaz de, por ejemplo, compilar el código de depuración, escribiendo una DEBUG #define

Otro uso de estas cosas lógicas, es evitar el doble incluye ...

Ejemplo, el archivo A, # incluye el archivo B y C. Pero el archivo B también incluye C.Esto probablemente dará como resultado un error de compilación, porque "C" existe dos veces.

La solución es escribir:

#ifndef C_FILE_INCLUDED 
#define C_FILE_INCLUDED 

//the contents of header "c" go here. 

#endif 

El otro uso de #define, es hacer que las macros.

Los más simples, consisten en sustituciones simples, como:

#define PI 3.14159265 

float perimeter(float radius) { 
    return radius*2*PI; 
} 

o

#define SHOW_ERROR_MESSAGE printf("An serious error happened"); 

if (1 != 1) { SHOW_ERROR_MESSAGE } 

, entonces también puede hacer que las macros que aceptan argumentos, printf sí generalmente es una macro, creada con a #define en un archivo de encabezado.

Pero esto no se debe hacer, por dos razones: primero, la velocidad os macros, es lo mismo que usar en línea, y segundo, tenemos plantillas C++, que permiten un mayor control sobre las funciones con tipo de variable. Por lo tanto, la única razón para utilizar macros con argumentos, es hacer construcciones extrañas, que serán difíciles de comprender más tarde, como la materia metaprogrammed ...

+0

Guau, tardé una eternidad en escribir mi publicación, ahora parece que acabo de copiar las publicaciones de dos tipos anteriores y las hice trizas en una :( – speeder

2

El uso más común (por el momento ) de #define es para incluir guardias :

// header.hh 
#ifndef HEADER_HH_ 
#define HEADER_HH_ 

namespace pony { 
// ... 
} 

#endif 

Otro uso común de #define es en la creación de un archivo de configuración, normalmente un archivo config.h, donde #define macros basa en diversos estados y condiciones. Luego, en nuestro código, probamos estas macros con #ifdef, #elif defined() etc. para admitir diferentes compilaciones para diferentes situaciones. Esto no es tan sólido como el modismo de incluir-guardia y debe tener cuidado aquí, porque si la bifurcación es incorrecta, entonces puede obtener errores de compilador muy oscuros, o peor, el comportamiento del tiempo de ejecución.

En general, excepto para incluir guardias que hay que pensar a (dos veces, preferentemente) sobre el problema, y ​​ver si se puede usar el compilador más que el preprocesador para resolverlo. El compilador es simplemente más inteligente que el preprocesador. No solo eso, sino que el compilador posiblemente no puede confundir al preprocesador, mientras que el preprocesador definitivamente puede confundir y engañar al compilador.

0

La mayoría de cosas sobre #defines han dicho ya, pero no es claro que C++ tiene mejores reemplazos para la mayoría de sus usos:

  1. #define para definir constantes numéricas pueden ser reemplazados fácilmente por una variable const" ", que, como #define, no existe realmente en el ejecutable compilado. AFAIK se puede usar en casi todas las situaciones en las que podría usar una constante numérica # definida, incluidos los límites de la matriz. La principal ventaja para mí es que tales constantes están claramente tipadas, por lo que no es necesario agregar conversiones en las macros "solo para estar seguro", y tienen un alcance, para que puedan mantenerse en espacios de nombres/clases/funciones, sin contaminar todo solicitud.

 

const int max_array_size=50; 
int an_array[max_array_size]; 
  1. #define para crear macros: las macros a menudo pueden ser sustituidas por las plantillas; por ejemplo, la temida MAX macro

 

#define MAX(a,b) ((a)<(b)?(b):(a)) 

, que tiene varias desventajas (por ejemplo, repetida evaluación argumentos, la expansión en línea inevitable), puede ser sustituida por la función max

template<typename T> T & max(T & a, T & b) 
{ 
    return a<b?b:a; 
} 

que puede ser seguro (en esta versión, los dos argumentos están forzados a ser del mismo tipo), se puede expandir tanto en línea como no (es decisión del compilador), evalúa los argumentos solo una vez (cuando se llama) y tiene un alcance. Se puede encontrar una explicación más detallada here.

Aún así, todavía macros deben ser usados ​​para incluir guardias, para crear algún tipo de extensiones de lenguaje extraños que se expanden a más línea de código, que tienen paréntesis desequilibrada, etc.

1

En C++, #define tiene muy estrecho , funciones especializadas: guardias

  • de cabecera, que se describen en otras respuestas
  • Interactuar con las bibliotecas estándar. Por ejemplo, #definir WINDOWS_LEAN_AND_MEAN antes de incluir windows.h desactiva ciertas macros problemáticas como MAX.
  • Macros avanzadas que implican la formación de cadenas (es decir, macros que imprimen mensajes de depuración) o pegado de fichas.

Debe evitar usando #define para los siguientes propósitos. Las razones son muchas; ver para el instance this FAQ entry.

  • Constantes de tiempo de compilación. Use const en su lugar.
  • Funciones de macro simples. Use las funciones y plantillas inline en su lugar.
Cuestiones relacionadas