"static const" vs " # define "vs" enum"


¿Cuál es mejor usar entre las siguientes declaraciones en C?

static const int var = 5;

O

#define var 5

O

enum { var = 5 };
 490
Author: Housy, 2009-11-04

17 answers

En términos generales:

static const

Porque respeta el alcance y es seguro para el tipo.

La única advertencia que pude ver: si desea que la variable se defina posiblemente en la línea de comandos. Todavía hay una alternativa:

#ifdef VAR // Very bad name, not long enough, too general, etc..
  static int const var = VAR;
#else
  static int const var = 5; // default value
#endif

Siempre que sea posible, en lugar de macros / puntos suspensivos, utilice una alternativa segura de tipos.

Si realmente necesita ir con una macro (por ejemplo, desea __FILE__ o __LINE__), entonces será mejor que nombre su macro CON mucho cuidado: en su nombre convención Boost recomienda todas las mayúsculas, comenzando por el nombre del proyecto (aquí BOOST_), mientras hojea la biblioteca notará que esto es (generalmente) seguido por el nombre del área en particular (biblioteca) y luego con un nombre significativo.

Generalmente hace que los nombres sean largos:)

 258
Author: Matthieu M.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-02 09:09:48

Depende de para qué se necesita el valor. Usted (y todos los demás hasta ahora) omitieron la tercera alternativa:

  1. static const int var = 5;
  2. #define var 5
  3. enum { var = 5 };

Ignorando cuestiones sobre la elección del nombre, entonces:

  • Si necesita pasar un puntero, debe usar (1).
  • Dado que (2) es aparentemente una opción, no necesita pasar punteros.
  • Tanto (1) como (3) tienen un símbolo en la tabla de símbolos del depurador, lo que facilita la depuración. Se es más probable que (2) no tenga un símbolo, dejándote preguntándote qué es.
  • (1) no se puede usar como una dimensión para matrices en el ámbito global; tanto (2) como (3) pueden.
  • (1) no se puede usar como una dimensión para matrices estáticas en el ámbito de la función; tanto (2) como (3) pueden.
  • Bajo C99, todos estos pueden ser usados para arrays locales. Técnicamente, usar (1) implicaría el uso de un VLA (array de longitud variable), aunque la dimensión referenciada por 'var' por supuesto se fijaría en tamaño 5.
  • (1) no se puede usar en lugares como las sentencias switch; tanto (2) como (3) pueden.
  • (1) no se puede usar para inicializar variables estáticas; tanto (2) como (3) pueden.
  • (2) puede cambiar el código que no quería cambiar porque es utilizado por el preprocesador; tanto (1) como (3) no tendrán efectos secundarios inesperados como ese.
  • Puede detectar si (2) se ha establecido en el preprocesador; ni (1) ni (3) lo permite.

Así que, en la mayoría de los contextos, prefieren la 'enumeración' sobre las alternativas. De lo contrario, es probable que el primer y el último punto sean los factores que controlan, y debe pensar más si necesita satisfacer ambos a la vez.

Si estuviera preguntando sobre C++, entonces usaría la opción (1) - la const estática - cada vez.

 589
Author: Jonathan Leffler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-04 18:22:11

En C, específicamente? En C la respuesta correcta es: use #define (o, si procede, enum)

Si bien es beneficioso tener las propiedades de alcance y tipificación de un objeto const, en realidad los objetos const en C (a diferencia de C++) no son constantes verdaderas y, por lo tanto, generalmente son inútiles en la mayoría de los casos prácticos.

Entonces, en C la elección debe ser determinada por cómo planeas usar tu constante. Por ejemplo, no puede usar un objeto const int como una etiqueta case (mientras que una macro trabajo). No puede usar un objeto const int como un ancho de campo de bits (mientras que una macro funcionará). En C89 / 90 no se puede usar un objeto const para especificar un tamaño de matriz (mientras que una macro funcionará). Incluso en C99 no se puede usar un objeto const para especificar un tamaño de matriz cuando se necesita una matriz no-VLA.

Si esto es importante para usted, entonces determinará su elección. La mayoría de las veces, no tendrá más remedio que usar #define en C. Y no olvide otra alternativa, que produce constantes verdaderas en C - enum.

En C++ const los objetos son constantes verdaderas, por lo que en C++ casi siempre es mejor preferir la variante const (sin necesidad de static explícito en C++).

 94
Author: AnT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-02 09:16:39

La diferencia entre static const y #define, es que el primero utiliza la memoria y la posterior no utilizar la memoria para almacenamiento. En segundo lugar, no se puede pasar la dirección de un #define mientras que se puede pasar la dirección de un static const. En realidad, dependiendo de las circunstancias en las que nos encontremos, necesitamos seleccionar una de estas dos. Ambos están en su mejor momento bajo diferentes circunstancias. Por favor, no asumas que uno es mejor que el otro... :-)

Si ese hubiera sido el caso, Dennis Ritchie habría mantenido al mejor solo... jajaja... :-)

 28
Author: wrapperm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-02 09:30:06

En C #define es mucho más popular. Puede usar esos valores para declarar tamaños de matriz, por ejemplo:

#define MAXLEN 5

void foo(void) {
   int bar[MAXLEN];
}

ANSI C no le permite usar static consts en este contexto que yo sepa. En C++ se deben evitar las macros en estos casos. Puedes escribir

const int maxlen = 5;

void foo() {
   int bar[maxlen];
}

E incluso omitir static porque el enlace interno está implícito en const ya [solo en C++].

 14
Author: sellibitze,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-21 21:06:11

Otro inconveniente de const en C es que no puede usar el valor para inicializar otro const.

static int const NUMBER_OF_FINGERS_PER_HAND = 5;
static int const NUMBER_OF_HANDS = 2;

// initializer element is not constant, this does not work.
static int const NUMBER_OF_FINGERS = NUMBER_OF_FINGERS_PER_HAND 
                                     * NUMBER_OF_HANDS;

Incluso esto no funciona con una const ya que el compilador no la ve como una constante:

static uint8_t const ARRAY_SIZE = 16;
static int8_t const lookup_table[ARRAY_SIZE] = {
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; // ARRAY_SIZE not a constant!

Estaría encantado de usar typed const en estos casos, de lo contrario...

 13
Author: Gauthier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-24 13:32:02

Si puedes salirte con la tuya, static const tiene muchas ventajas. Obedece a los principios de alcance normal, es visible en un depurador, y generalmente obedece las reglas que las variables obedecen.

Sin embargo, al menos en el estándar C original, en realidad no es una constante. Si usa #define var 5, puede escribir int foo[var]; como una declaración, pero no puede hacer eso (excepto como una extensión de compilador" con static const int var = 5;. Este no es el caso en C++, donde la versión static const se puede usar en cualquier lugar que la versión #define pueda, y creo que este es también el caso con C99.

Sin embargo, nunca nombre una constante #define con un nombre en minúsculas. Anulará cualquier posible uso de ese nombre hasta el final de la unidad de traducción. Las constantes de macro deben estar en lo que efectivamente es su propio espacio de nombres, que es tradicionalmente todas las letras mayúsculas, tal vez con un prefijo.

 9
Author: David Thornley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-04 14:38:24

Escribí un programa de prueba rápida para demostrar una diferencia:

#include <stdio.h>

enum {ENUM_DEFINED=16};
enum {ENUM_DEFINED=32};

#define DEFINED_DEFINED 16
#define DEFINED_DEFINED 32

int main(int argc, char *argv[]) {

   printf("%d, %d\n", DEFINED_DEFINED, ENUM_DEFINED);

   return(0);
}

Esto compila con estos errores y advertencias:

main.c:6:7: error: redefinition of enumerator 'ENUM_DEFINED'
enum {ENUM_DEFINED=32};
      ^
main.c:5:7: note: previous definition is here
enum {ENUM_DEFINED=16};
      ^
main.c:9:9: warning: 'DEFINED_DEFINED' macro redefined [-Wmacro-redefined]
#define DEFINED_DEFINED 32
        ^
main.c:8:9: note: previous definition is here
#define DEFINED_DEFINED 16
        ^

Tenga en cuenta que enum da un error cuando define da una advertencia.

 6
Author: Michael Potter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-29 17:37:40

#define var 5 te causará problemas si tienes cosas como mystruct.var.

Por ejemplo,

struct mystruct {
    int var;
};

#define var 5

int main() {
    struct mystruct foo;
    foo.var = 1;
    return 0;
}

El preprocesador lo reemplazará y el código no se compilará. Por esta razón, el estilo de codificación tradicional sugiere que todas las constantes #defineusan letras mayúsculas para evitar conflictos.

 5
Author: Non-maskable Interrupt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-02 09:33:26

Siempre es preferible usar const, en lugar de #define. Esto se debe a que const es tratado por el compilador y #define por el preprocesador. Es como si # define en sí no fuera parte del código (en términos generales).

Ejemplo:

#define PI 3.1416

El nombre simbólico PI nunca puede ser visto por los compiladores; puede ser eliminado por el preprocesador antes de que el código fuente llegue a un compilador. Como resultado, es posible que el nombre PI no se ingrese en la tabla de símbolos. Esto puede ser confuso si obtiene un error durante la compilación que involucra el uso de la constante, porque el mensaje de error puede referirse a 3.1416, no a PI. Si PI estuviera definido en un archivo de encabezado que no escribiste, no tendrías idea de dónde vino ese 3.1416.

Este problema también puede aparecer en un depurador simbólico, porque, de nuevo, el nombre con el que está programando puede no estar en la tabla de símbolos.

Solución:

const double PI = 3.1416; //or static const...
 5
Author: suren,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-01 17:48:29

La definición

const int const_value = 5;

No siempre define un valor constante. Algunos compiladores (por ejemplo tcc 0.9.26) solo asignan memoria identificada con el nombre "const_value". Usando el identificador "const_value" no se puede modificar esta memoria. Pero todavía podría modificar la memoria usando otro identificador:

const int const_value = 5;
int *mutable_value = (int*) &const_value;
*mutable_value = 3;
printf("%i", const_value); // The output may be 5 or 3, depending on the compiler.

Esto significa la definición

#define CONST_VALUE 5

Es la única manera de definir un valor constante que no puede ser modificado por ningún medio.

 4
Author: user2229691,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-01 17:44:02

No creo que haya una respuesta para "lo que siempre es mejor", pero, como dijo Matthieu

static const

Es tipo seguro. Mi mayor molestia con #define, sin embargo, es cuando la depuración en Visual Studio no se puede ver la variable. Da un error que el símbolo no se puede encontrar.

 3
Author: Afcrowe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-02 09:11:19

Por cierto, una alternativa a #define, que proporciona un alcance adecuado pero se comporta como una constante "real", es "enum". Por ejemplo:

enum {number_ten = 10;}

En muchos casos, es útil definir tipos enumerados y crear variables de esos tipos; si se hace, los depuradores pueden mostrar variables de acuerdo con su nombre de enumeración.

Una advertencia importante al hacer eso, sin embargo: en C++, los tipos enumerados tienen una compatibilidad limitada con los enteros. Por ejemplo, por defecto, uno no puede realizar aritmética sobre ellos. Me parece que es un comportamiento predeterminado curioso para enumeraciones; mientras que habría sido bueno tener un tipo "enumeración estricta", dado el deseo de tener C++ generalmente compatible con C, creo que el comportamiento predeterminado de un tipo "enumeración" debería ser intercambiable con enteros.

 3
Author: supercat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-02 09:32:14

Aunque la pregunta era sobre enteros, vale la pena señalar que #define y enums son inútiles si necesita una estructura constante o cadena. Ambos se pasan generalmente a funciones como punteros. (Con cadenas es necesario; con estructuras es mucho más eficiente.)

En cuanto a los enteros, si se encuentra en un entorno embebido con memoria muy limitada, es posible que deba preocuparse por dónde se almacena la constante y cómo se compilan los accesos a ella. El compilador podría agregar dos consts en tiempo de ejecución ,pero añadir dos # define en tiempo de compilación. Una constante # define puede convertirse en una o más instrucciones MOV [inmediatas], lo que significa que la constante se almacena efectivamente en la memoria del programa. Una constante const se almacenará en el .sección const en la memoria de datos. En sistemas con una arquitectura de Harvard, podría haber diferencias en el rendimiento y el uso de memoria, aunque probablemente serían pequeñas. Pueden ser importantes para la optimización del núcleo duro de los bucles internos.

 2
Author: Adam Haun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-05 21:17:24

Una simple diferencia:

En el tiempo de preprocesamiento, la constante se reemplaza con su valor. Por lo tanto, no puede aplicar el operador de desreferencia a una definición, pero puede aplicar el operador de desreferencia a una variable.

Como se supone, definir es más rápido que const estática.

Por ejemplo, teniendo:

#define mymax 100

No puedes hacer printf("address of constant is %p",&mymax);.

Pero teniendo

const int mymax_var=100

Puedes hacer printf("address of constant is %p",&mymax_var);.

Para ser más claro, la definición se sustituye por su valor en el etapa de pre-procesamiento, por lo que no tenemos ninguna variable almacenada en el programa. Solo tenemos el código del segmento de texto del programa donde se usó la definición.

Sin embargo, para const estática tenemos una variable que está asignada en algún lugar. Para gcc, const estática se asignan en el segmento de texto del programa.

Anteriormente, quería hablar sobre el operador de referencia, así que reemplace la desreferencia con referencia.

 1
Author: mihaitzateo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-01 17:47:12

Observamos el código ensamblador producido en el MBF16X... Ambas variantes dan como resultado el mismo código para operaciones aritméticas (AGREGAR Inmediato, por ejemplo).

Así que const int se prefiere para la comprobación de tipo, mientras que #define es de estilo antiguo. Tal vez sea específico del compilador. Así que compruebe su código ensamblador producido.

 0
Author: guest,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-01 17:49:24

No estoy seguro de si tengo razón, pero en mi opinión llamar a #defineel valor d es mucho más rápido que llamar a cualquier otra variable declarada normalmente (o valor const). Es porque cuando el programa se está ejecutando y necesita usar alguna variable normalmente declarada necesita saltar al lugar exacto en la memoria para obtener esa variable.

Al contrario, cuando usa #define el valor d, el programa no necesita saltar a ninguna memoria asignada, solo toma el valor. Si #define myValue 7 y el programa que llama myValue, se comporta exactamente lo mismo que cuando simplemente llama 7.

 0
Author: pajczur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-10-05 19:59:49