2009-12-22 19 views

Respuesta

17

Las constantes le permiten especificar un tipo de datos, que es (generalmente) una ventaja. Las macros son mucho más flexibles y, por lo tanto, pueden ocasionarte más problemas si no tienes cuidado.

La mejor práctica es usar constantes tanto como sea posible, y use #define solo cuando realmente necesite una macro, no solo un valor literal con nombre.

+17

-1 por no mencionar que 'const' en C no es una constante (en tiempo de compilación) verdadera y, por lo tanto, no se puede usar en etiquetas' case', como tamaños de matriz, y en otros contextos donde se requiere una expresión constante. Hay una razón por la cual '# define' se utiliza tan fuertemente en C (y' const' se usa mucho más a menudo en C++), y pasarlo por alto hace una mala respuesta a esta pregunta. –

+0

Olvidé que la const es más débil en C como mencionas, pero creo que la mejor práctica es usar consts siempre que sea posible. –

+4

IMO, la mejor opción es utilizar realmente un 'enum' anónimo para esas expresiones constantes integrales; es un poco tipeado, tiene un alcance, sin nombre, etc., pero también es una constante integral. Para todo lo demás (para lo que el tiempo de compilación en realidad no importa - flotadores, cadenas, etc.), 'const' está bien. También tenga en cuenta que las enumeraciones anónimas están en ANSI C89, aunque muchas personas creen lo contrario (ya que las estructuras anónimas no están allí). –

3

Las constantes siguen las medidas de seguridad del tipo, #defines se sustituyen por completo. También como dijo GMan, # define no respeta el alcance.

17

en realidad hay tres maneras de definir tales constantes,

  • define

  • enums
  • variables de const

En C, todo es un int menos que se especifique lo contrario. Prefiero las enumeraciones cuando tengo un número de constantes enteras relacionadas. Los enums son claramente preferibles cuando no te importan los valores. Pero incluso cuando necesitas especificar los valores para todas las constantes, me gusta la agrupación mental de una enumeración. El código se documenta mejor cuando tiene el tipo, p.

Error MyFunc(); 

vuelve claramente uno de un conjunto particular de códigos de error, mientras que

int MyFunc() 

podría devolver uno de la lista que se defina # errno para Unix, o tal vez algo más, o tal vez los más algo valores idiosincrásicos, ¿quién sabe? Si tiene más de un conjunto de códigos de retorno, ¿qué conjunto utiliza esta función?

El nombre de tipo de enumeración más específico ayuda a la instalación de las etiquetas en su editor, greps, depuración, etc.

Una pelusa estricta puede advertirle sobre el uso de enumeraciones como enteros, por ejemplo, si agrega yo, o si pasa una enumeración a una int.

Un objeto const es diferente de una enum o una #define, particularmente en C. En ANSI C, una const int ocupa espacio como una int normal; la mayoría de los compiladores también generarán referencias de puntero a esta dirección en lugar de subrayar el valor. Como resultado, rara vez uso const int en C. (C++ tiene una semántica ligeramente diferente, por lo que las opciones son diferentes).

Cada compilador que he usado tiene la opción de almacenar enumeraciones en el menor espacio posible . Por lo general, incluso es la opción predeterminada. Para forzar enumeraciones más amplias cuando se utiliza esta opción, por lo general tirar un valor sin signo adicional:

typedef enum 
{ 
    MyEnumA, 
    MyEnumB, 

    MyEnumForce16 = 7fff 
} MyEnum; 

El uso de una constante de enumeración (enum) tiene muchas ventajas sobre el uso del estilo constante simbólica tradicional de #define. Estas ventajas incluyen un menor requisito de mantenimiento, una mejor legibilidad del programa y una mejor capacidad de depuración.

1) La primera ventaja es que las constantes enumeradas se generan automáticamente por el compilador.Por el contrario, las constantes simbólicas deben ser valores asignados manualmente por el programador.

Por ejemplo, si ha tenido una constante el tipo enumerado para los códigos de error que pueden ocurrir en su programa, su definición de enumeración podría ser algo como esto:

enum Error_Code 
{ 
OUT_OF_MEMORY, 
INSUFFICIENT_DISK_SPACE, 
LOGIC_ERROR, 
FILE_NOT_FOUND 
}; 

En el ejemplo anterior, OUT_OF_MEMORY se le asigna automáticamente el valor de 0 (cero) por el compilador porque aparece primero en la definición. El compilador continúa asignando automáticamente números a las constantes enumeradas, haciendo que INSUFFICIENT_DISK_SPACE sea igual a 1, LOGIC_ERROR igual a 2 y FILE_NOT_FOUND igual a 3, y así sucesivamente. Si se va a abordar el mismo ejemplo mediante el uso de constantes simbólicas, su código sería algo como esto:

#define OUT_OF_MEMORY 0 
#define INSUFFICIENT_DISK_SPACE 1 
#define LOGIC_ERROR 2 
#define FILE_NOT_FOUND 3 

Cada uno de los dos métodos llega al mismo resultado: cuatro constantes asignados valores numéricos para representar los códigos de error. Tenga en cuenta el mantenimiento requerido, sin embargo, si tuviera que agregar dos constantes para representar los códigos de error DRIVE_NOT_READY y CORRUPT_FILE. Usando el método de constante de enumeración, simplemente pondría estas dos constantes en cualquier lugar de la definición de enum. El compilador generaría dos valores únicos para estas constantes. Usando el método de la constante simbólica, debería asignar manualmente dos números nuevos a estas constantes. Además, querrá asegurarse de que los números que asigne a estas constantes sean únicos.

2) Otra ventaja de utilizar el método de enumeración constante es que sus programas son más legibles y, por lo tanto, pueden ser mejor entendidos por otros que podrían tener que actualizar su programa más adelante.

3) Una tercera ventaja de usar constantes de enumeración es que algunos depuradores simbólicos pueden imprimir el valor de una constante de enumeración. Por el contrario, la mayoría de los depuradores simbólicos no pueden imprimir el valor de una constante simbólica. Esto puede ser una gran ayuda en la depuración de su programa, ya que si su programa se detiene en una línea que utiliza una enumeración, simplemente puede inspeccionar esa constante y saber al instante su valor. Por otro lado, como la mayoría de los depuradores no pueden imprimir los valores #define, lo más probable es que tenga que buscar ese valor buscándolo manualmente en un archivo de encabezado.

La declaración #define es una directiva de precompilación. Técnicamente, cualquier línea que comience con un # es algo sobre lo que el precompilador puede actuar. El precompilador reemplazará todas las instancias del token definido con su definición. Así que hacer esto:

#define DELAY 40 
for (i=0;i<DELAY;i++) { 
    for (j=0;j<DELAY;j++) { 
     asm NOP; 
    } 
} 

es exactamente lo mismo que esto (por lo que el compilador se refiere):

for (i=0;i<40;i++) { 
    for (j=0;j<40;j++) { 
     asm NOP; 
    } 
} 

Cuando el compilador genera código máquina, se verá el número 40 y el uso de la modo de direccionamiento inmediato para comparar con el acumulador. El número 40 se almacenará en el código tantas veces como lo referencia. En este caso, es dos veces. Aquí está el conjunto generado por CodeWarrior Ver5:

7: char i,j; 
    8: for (i=0;i<DELAY;i++) { 
    0002 95  [2]    TSX 
    0003 7f  [2]    CLR ,X 
    0004   [5]  L4:  
    9:  for (j=0;j<DELAY;j++) { 
    0004 6f01  [3]    CLR 1,X 
    0006   [5]  L6:  
    10:  asm NOP; 
    0006 9d  [1]    NOP 
    0007 6c01  [4]    INC 1,X 
    0009 e601  [3]    LDA 1,X 
    000b a128  [2]    CMP #40 ;<---- notice opcode a1 and immediate constant 40, which is $28 in hexadecimal 
    000d 25f7  [3]    BCS L6 
    000f 7c  [3]    INC ,X 
    0010 f6  [2]    LDA ,X 
    0011 a128  [2]    CMP #40 ;<---- and here it is again. 
    0013 25ef  [3]    BCS L4 
    11:  } 
    12: } 
    13: } 
+2

+1 para listar todas las opciones disponibles, pero vale la pena ampliar el beneficio de usar 'enum', y la desventaja de' const' en comparación con 'enum' y' # define'. –

4

constantes tienen la ventaja de estar mecanografiado, por lo que su uso incorrecto puede ser descubiertos en tiempo de compilación. Puede que no le importe, pero las constantes ocupan espacio en la memoria, mientras que las definiciones # no (ya que se reemplazan antes de que ocurra la compilación real).

+3

Las constantes no necesitan ocupar espacio en la memoria, si no toma su dirección (o si no las trata como valores l). Cualquier enlazador sano optimizará cualquier tal lejos. –

0

Const es un objeto que puede tomar su dirección, por ejemplo. También es seguro para tipos, es decir, el compilador sabe cuál es el tipo de constante. arriba no se aplica a #define.

0
  1. const produce un lvalue, lo que significa que su dirección puede tomarse. #define no.
  2. #define puede causar macro expansiones involuntarias, que pueden ser un error de depuración de PITA.
  3. Según lo mencionado por otros, #define no tiene un tipo asociado.

En general, yo evitaría el preprocesador como la peste por cualquier cosa que no tenía que usarlo para, sobre todo debido a la posibilidad de expansión no intencionada y debido a la convención ALL_CAPS para mitigar esto es increíblemente feo.

25

As 0A0D mentioned, hay #defines, enums y const variables. Vale la pena señalar que las variables calificadas const no se consideran constantes de tiempo de compilación en C y, por lo tanto, no se pueden usar en algunas circunstancias (por ejemplo, al declarar el tamaño de una matriz).

enum Las constantes son constantes de tiempo de compilación, sin embargo. Para valores integrales, IMO generalmente es mejor preferir enums sobre const variables sobre #define.

+3

Estoy sorprendido de que la única respuesta que señala correctamente la clara desventaja de usar 'const' en C (y, por extensión, Objective-C; tenga en cuenta que esta pregunta no es sobre C++!) No se transmite al parte superior. +1, y desearía poder dar esto más. –

+5

Por lo tanto, para resumir, la regla breve es: para las constantes integrales, use enumeraciones anónimas. Para todo lo demás, usa 'const'. No use '# define' a excepción de las macros apropiadas, o tokens condicionalmente incluidos. –

+0

¿Qué son enum anónimos? – Michael

1

Explicación para #define: A #define es un valor inmediato o una macro.

Explicación de la constante: Una constante es un valor de cualquier tipo que nunca puede cambiar.

Puede delcare un puntero a una constante, pero no a un #define, aunque un #define podría ser un puntero por ejemplo: DIRECCIÓN #define ((int *) 0x0012)

Entonces ¿por qué deberíamos el uso constante es la siguiente:

  • que obedecen a reglas de alcance de la lengua
  • se pueden ver en el depurador
  • puede tomar su dirección si es necesario
  • puede pasarlos por const-reference si necesita
  • No crean nuevas "palabras clave" en su programa.

En resumen, los identificadores const actúan como si fueran parte del idioma porque son parte del idioma.

Dentro de un módulo, un compilador de C podría optimizar una constante como si fuera un #define, si no hay punteros declarados a la constante. En términos de CPU, la const se convertiría en un valor "inmediato". Otras alternativas es que una variable const podría ser colocada en el área de código en lugar de en el área de datos, ya que no cambia. En algunas máquinas, declarar un ponter a una constante podría causar una excepción si intenta modificar la constante mediante el puntero.

Hay casos donde #define es necesario, pero en general debe evitarlo cuando lo desee.Debe evaluar si usa const o #define según el valor comercial: tiempo, dinero, riesgo.

0

1) # define's se pueden considerar como parámetros ajustables que son independientes de los tipos de datos, mientras que las constantes nos permiten mencionar el tipo de datos.

2) # define reemplaza cualquier código que sigue al del programa principal donde sea que se mencionen. Además de esto, incluso podemos tener la función macro realizando una tarea específica, que podría llamarse pasando los parámetros solo. Obviamente, estos no son posibles en el caso de las constantes.

Por lo tanto, se utilizan según la relevancia.

0

la ventaja de usar define es que una vez que defines la variable para exp: #define NUMBER 30, todo el código en main usará ese código con el valor 30. Si cambias el 30 a 40 cambiará directamente todo el valor en principal que usa esta variable (NÚMERO).