¿Se puede usar una variable const para declarar el tamaño de una matriz en C?

¿Por qué el siguiente código arroja un error?

const int a = 5; int b[a]={1,2,3,4,5}; 

Y también cuando intenté comstackr el código anterior sin la palabra clave “const”, obtuve el mismo error:

 int a = 5; int b[a]={1,2,3,4,5}; 

¿por que es esto entonces? ¿Cuál es el error que estoy haciendo aquí?

Y también otra pregunta: ¿Cuándo se reemplazan las constantes con sus valores reales en un código, es decir, si declaro una variable, digamos: const int x = 5; Sé que no se asigna memoria en la RAM para la variable x, pero el área de la variable constante en la ROM tiene el valor 5 y que x simplemente se reemplaza por el valor 5 dondequiera que x aparezca en el código. Pero cuando sucede esto? Tiempo de comstackción? Tiempo de arranque? Tiempo de preprocesamiento?

PD: estoy hablando de Embedded C (ejecutándose en un Microcontrolador, etc.), no C funcionando en mi escritorio. Por lo tanto, el sistema integrado debe tener una ROM (Flash, EEPROM …). ¿Qué pasaría entonces?

Es simplemente una limitación del lenguaje. Los tamaños de las matrices acotadas estáticamente deben ser expresiones constantes , y desafortunadamente en C eso es solo algo así como una constante literal o un sizeof expresión o similar, pero no una variable de tipo const .

(Como señaló Simon, desde C99 también existen matrices acotadas en tiempo de ejecución , o “matrices de longitud variable”, cuyo tamaño puede estar dado por el valor de cualquier variable. Pero ese es un animal diferente).

Puede que le interese saber que las reglas son diferentes en C ++, donde una static const int es de hecho una expresión constante, y C ++ 11 incluso agrega una nueva palabra clave, constexpr , para permitir un uso aún más general de las expresiones constantes que abarcan más cosas cuyo valor “podría razonablemente determinarse en el momento de la comstackción”.

En C, const es un nombre inapropiado para solo lectura . const variables const pueden cambiar su valor, por ejemplo, está perfectamente bien declarar

 const volatile int timer_tick_register; /* A CPU register. */ 

que puede leer y obtener un valor diferente con cada lectura, pero no escribir en. Por lo tanto, la especificación del lenguaje trata los objetos const calificados no como expresiones constantes adecuadas para tamaños de matriz.

2 alternativas principales al VLA: enum y macros

Con enum :

 enum N { N = 5 }; int is[N]; 

Esto funciona porque los miembros enum son expresiones constantes: ¿el miembro enum puede ser del tamaño de una matriz en ANSI-C?

Con macros:

 #define N 5 int is[N]; 

La ventaja de enum s es que las enum tienen scope y son parte del paso de comstackción, por lo que también pueden generar mejores mensajes de error.

La ventaja de las macros es que tienes más control sobre el tipo de las constantes (por ejemplo, #define N 1 vs #define N 1u ), mientras que las enum se fijan a algún tipo definido de implementación: Is the sizeof (enum) == sizeof ( int), siempre? Pero no importa mucho en este caso.

Por qué evitar VLA

  • no están en C89, y solo son opcionales en C11
  • puede incurrir en una sobrecarga: ¿hay alguna sobrecarga para usar arrays de longitud variable? (Probablemente poco)

EDITAR: Solo lee en la wikipedia que C11 ha relegado las matrices de longitud variable a una función opcional 🙁 Doh! La primera mitad de la publicación puede no ser tan útil, pero la segunda mitad responde algunas de tus otras preguntas 🙂

Como extra a la publicación de Kerrek SB, C99 (ISO / IEC 9899: 1999) tiene el concepto de una matriz de longitud variable . La norma brinda el siguiente ejemplo:

 #include  size_t fsize3(int n) { char b[n+3]; // variable length array return sizeof b; // execution time sizeof } 

El operador sizeof se extiende de la siguiente manera:

El operador sizeof produce el tamaño (en bytes) de su operando, que puede ser una expresión o el nombre entre paréntesis de un tipo. El tamaño se determina a partir del tipo de operando. El resultado es un entero. Si el tipo del operando es un tipo de matriz de longitud variable, se evalúa el operando ; de lo contrario, el operando no se evalúa y el resultado es una constante entera.

Otro buen ejemplo se puede encontrar en wikipedia .

Tenga en cuenta que las matrices declaradas estáticamente no pueden ser de longitud variable.

En cuanto a algunas de sus otras preguntas:

P: ¿Cuándo se reemplazan las constantes con sus valores reales en un código?

Si la constante es una variable const entonces nunca puede ser “reemplazada” y siempre se puede acceder como un área de memoria. Esto se debe a que el operador de dirección & todavía tiene que trabajar con la variable. Sin embargo, si la dirección de la variable nunca se utiliza, puede “reemplazarse” y no tener memoria asignada. Del estándar C:

La implementación puede colocar un objeto const que no sea volátil en una región de almacenamiento de solo lectura. Además, la implementación no necesita asignar almacenamiento para tal objeto si su dirección nunca se usa.

Próxima pregunta…

P: Sé que no se asigna memoria en la RAM para la variable x, pero el área de variable constante en la ROM tiene el valor 5

Esto depende de tu sistema. Si tiene ROM y el comstackdor sabe dónde se encuentra la ROM, entonces puede colocarse en la ROM. Si no hay ROM, la única opción que tendrá el comstackdor (bueno, el vinculador) es la memoria RAM.

Q: x simplemente se reemplaza por el valor 5 dondequiera que x aparezca en el código. Pero cuando sucede esto? Tiempo de comstackción? Tiempo de arranque? Tiempo de preprocesamiento?

Como se señaló, esto más bien depende de cómo se usa la constante. Si la dirección de la variable const nunca se utiliza y el comstackdor es lo suficientemente inteligente, entonces en el momento del cumplimiento. De lo contrario, el “reemplazo” nunca ocurre y es un valor con una ubicación en la memoria; en este caso, la ubicación de la variable en la memoria ocurre en el tiempo del enlace. Nunca ocurrirá durante el preprocesamiento.

Tal vez vale la pena mencionar, aquí podría usar

 int b[] = {1, 4, 5}; 

En caso de que necesites cantidad de elementos

  size_t sz = sizeof(b)/sizeof(b[0]); 

Creo que depende de la cadena de herramientas, decidir dónde almacenar constantes, flash o RAM