¿Por qué la mayoría de los desarrolladores de C usan define en lugar de const? [duplicate]

9 minutos de lectura

avatar de usuario
Cruzar

En muchos programas un #define tiene el mismo propósito que una constante. Por ejemplo.

#define FIELD_WIDTH 10
const int fieldWidth = 10;

Por lo general, prefiero la primera forma sobre la otra, confiando en el preprocesador para manejar lo que es básicamente una decisión de aplicación. ¿Hay alguna razón para esta tradición?

  • Tenga en cuenta que para las constantes enteras, también puede usar una enumeración como en “enum {FIELD_WIDTH = 10};´´que puede ser útil si necesita una constante de tiempo de compilación en el alcance de una función.

    – Jochén Walter

    26 de octubre de 2010 a las 14:16


  • También puede #definir en el alcance de la función, aunque debe recordar #desdefinir al final de la función

    – CashCow

    26 de octubre de 2010 a las 14:58

  • @CashCow: Así es, pero entonces está anulando la definición de un posible #define en el alcance del archivo (que puede haber sido definido en un archivo de inclusión que no ha escrito usted mismo).

    – Jochén Walter

    26 de octubre de 2010 a las 15:18

  • @Jochen: cuando hay una colisión con otra definición de macro, entonces su #define ya ha sobrescrito la definición anterior y ha ignorado una advertencia del compilador, por lo que también puede #desdefinir y producir un error de compilación cuando se usa la macro más abajo en su código, para recordarle que debe cambiar el nombre de macro para su macro de alcance de función.

    – Seguro

    26 de octubre de 2010 a las 15:49

  • @Secure: Claro, pero luego tienes que manejar el conflicto de nombres. La ventaja de los ámbitos locales es que lo evitan. Por supuesto, usar una enumeración local tampoco es a prueba de balas: si un #define global reescribe FIELD_WIDTH a otra cosa, digamos 20, la enumeración se reescribirá a `enum {20 = 10};` Sin embargo, si la definición global y local de FIELD_WIDTH son enumeraciones, ambas definiciones coexisten (la definición local sombrea a la global). (Ver eetimes.com/discussion/programming-pointers/4023879/… para más información sobre este tema.

    – Jochén Walter

    26/10/2010 a las 19:59


Hay una razón muy sólida para esto: const en C no significa que algo sea constante. Simplemente significa que una variable es de solo lectura.

En lugares donde el compilador requiere una constante verdadera (como para tamaños de arreglo para arreglos que no son VLA), usando un const variable, como fieldWidth simplemente no es posible.

  • +1 para la respuesta correcta entre un mar de respuestas incorrectas de programadores de C++ que no conocen C.

    – R.. GitHub DEJA DE AYUDAR A ICE

    26 de octubre de 2010 a las 13:59

  • @C. Ross: Coherencia. Todas las constantes manifiestas generalmente se definen con #defines. const solo se usa para indicar una variable de solo lectura (ruta de acceso a una). Sé, const en C está simplemente roto 🙂

    –Bart van Ingen Schenau

    26 de octubre de 2010 a las 14:16

  • No puedes decir algo como const int size 4; y luego hacer char str[size]?

    usuario379888

    27 de octubre de 2010 a las 11:29

  • @fahad: No en C89. En C99 puede hacerlo por una variable de duración de almacenamiento automático, pero técnicamente es un VLA.

    – café

    27 de octubre de 2010 a las 12:01

  • @Excepción: C y C++ son lenguajes muy diferentes en su tratamiento de const. En C++, const se puede usar para constantes adecuadas, en C no se puede.

    –Bart van Ingen Schenau

    28 de octubre de 2010 a las 9:54

avatar de usuario
Vovanium

son diferentes

const es solo un calificador, que dice que una variable no se puede cambiar en tiempo de ejecución. Pero todas las demás características de la variable persisten: ha asignado almacenamiento y este almacenamiento puede abordarse. Entonces, el código no solo lo trata como un literal, sino que se refiere a la variable accediendo a la ubicación de memoria especificada (excepto si es static const, luego se puede optimizar) y cargar su valor en tiempo de ejecución. y como un const tiene almacenamiento asignado, si lo agrega a un encabezado y lo incluye en varias fuentes de C, obtendrá un error de vinculación de “definición de símbolo múltiple” a menos que lo marque como extern. Y en este caso, el compilador no puede optimizar el código contra su valor real (a menos que la optimización global esté activada).

#define simplemente sustituye un nombre con su valor. Además, un #define‘d constante puede usarse en el preprocesador: puede usarlo con #ifdef para hacer una compilación condicional basada en su valor, o usar el operador de cadena # para obtener una cadena con su valor. Y como el compilador conoce su valor en el momento de la compilación, puede optimizar el código en función de ese valor.

Por ejemplo:

#define SCALE 1

...

scaled_x = x * SCALE;

Cuándo SCALE Se define como 1 el compilador puede eliminar la multiplicación ya que sabe que x * 1 == xpero si SCALE es un (extern) const, necesitará generar código para obtener el valor y realizar la multiplicación porque el valor no se conocerá hasta la etapa de vinculación. (extern es necesario para usar la constante de varios archivos fuente).

Un equivalente más cercano a usar #define está usando enumeraciones:

enum dummy_enum {
   constant_value = 10010
};

Pero esto está restringido a valores enteros y no tiene ventajas de #definepor lo que no es muy utilizado.

const es útil cuando necesita importar un valor constante de alguna biblioteca donde se compiló. O si se usa con punteros. O si es una matriz de valores constantes a los que se accede a través de un valor de índice variable. De lo contrario, const no tiene ventajas sobre #define.

  • +1 por mencionar enum como alternativa, que debería usarse con mucha más frecuencia. Una gran ventaja es que el símbolo está disponible para el depurador.

    –Jonathan Leffler

    26 de octubre de 2010 a las 17:02

  • Prefiero pensar que es una desventaja del depurador no poder usar defines, en lugar de una ventaja de enumeración para que se pueda usar en el depurador.

    – Vovanium

    26 de octubre de 2010 a las 18:56

  • Y la ventaja de #define sobre enum es que tu puedes #ifdef probar su presencia o utilizar su valor en #iflo que lo hace mucho más útil para controlar las opciones de tiempo de compilación u ofrecer funciones que pueden estar presentes en algunas plataformas pero no en otras.

    – R.. GitHub DEJA DE AYUDAR A ICE

    26 de octubre de 2010 a las 19:27

  • Versiones más nuevas de gdb / gcc hacer apoyar el uso de #define constantes en el depurador (creo que el -gdb3 se debe pasar el indicador a gcc en el momento de la compilación para habilitar esto).

    – frotis

    3 de diciembre de 2010 a las 14:21


  • La parte sobre la optimización no es cierta para ningún compilador que haga optimización de tiempo de enlace.

    – Étienne

    30 de agosto de 2014 a las 15:37

La razón es que la mayoría de las veces, desea una constante, no un const-variable cualificada. Los dos no son ni remotamente iguales en el lenguaje C. Por ejemplo, las variables no son válidas como parte de los inicializadores para static-objetos de duración de almacenamiento, como dimensiones de matriz que no son VLA (por ejemplo, el tamaño de una matriz en una estructura o cualquier matriz anterior a C99).

  • ¿Algún otro caso de matriz no vla en C99 además de “matriz en una estructura”?

    – Por favor ayuda

    10/03/2015 a las 19:43

  • Matrices con duración de almacenamiento estático. Matrices de literales compuestos. Tipos de matrices utilizados en typedef con ámbito de archivo. Quizás otros.

    – R.. GitHub DEJA DE AYUDAR A ICE

    11 de marzo de 2015 a las 0:36

Ampliando un poco la respuesta de R: fieldWidth no es un expresión constante; es un const-variable cualificada. Su valor no se establece hasta el tiempo de ejecución, por lo que no se puede usar cuando se requiere una expresión constante en tiempo de compilación (como en una declaración de matriz o una etiqueta de caso en un switch declaración, etc).

Comparar con la macro FIELD_WIDTHque después del preprocesamiento se expande a la expresión constante 10; este valor es conocido en tiempo de compilación, por lo que puede usarse para dimensiones de matriz, etiquetas de casos, etc.

Para agregar a la respuesta de R. y Bart: solo hay una forma de definir constantes de tiempo de compilación simbólicas en C: constantes de tipo de enumeración. La norma impone que sean de tipo int. Yo personalmente escribiría tu ejemplo como

enum { fieldWidth = 10 };

Pero supongo que el gusto difiere mucho entre los programadores de C sobre eso.

avatar de usuario
Vaca Efectiva

Aunque una const int no siempre será apropiada, una enumeración generalmente funcionará como un sustituto de #define si está definiendo algo para que sea un valor integral. Esta es en realidad mi preferencia en tal caso.

enum { FIELD_WIDTH = 16384 };
char buf[FIELD_WIDTH];

En C ++, esta es una gran ventaja, ya que puede abarcar su enumeración en una clase o espacio de nombres, mientras que no puede abarcar un #define.

En C, no tiene espacios de nombres y no puede abarcar una enumeración dentro de una estructura, y ni siquiera estoy seguro de obtener la seguridad de tipo, por lo que en realidad no puedo ver ninguna ventaja importante, aunque tal vez algún programador de C me lo indique. .

avatar de usuario
Shlomi Loubatón

Según K&R (2ª edición, página 211), las “propiedades constantes y volátiles son nuevas con el estándar ANSI”. Esto puede implicar que el código ANSI realmente antiguo no tenía estas palabras clave en absoluto y realmente es solo una cuestión de tradición. Además, dice que un compilador debe detectar los intentos de cambiar las variables constantes, pero aparte de eso, puede ignorar estos calificadores. Creo que significa que algunos compiladores pueden no optimizar el código que contiene la variable const para que se represente como un valor intermedio en el código de la máquina (como lo hace #define) y esto podría costar más tiempo para acceder a la memoria lejana y afectar el rendimiento.

  • +1 por citar K&R pero -1 por responder que se trata de optimización en lugar de requisitos de idioma. Neto 0.

    – R.. GitHub DEJA DE AYUDAR A ICE

    26 de octubre de 2010 a las 15:19

  • No, implica que const y volatile fueron introducidos por el estándar ANSI C. La segunda edición de K&R se publicó antes de que se ratificara el estándar.

    – JeremyP

    26 de octubre de 2010 a las 15:21

  • Muchos programadores de C usan strchr para buscar un carácter en lugar de strtof porque strtof no se añadió hasta C99.

    – R.. GitHub DEJA DE AYUDAR A ICE

    26/10/2010 a las 19:30

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad