¿Por qué el tamaño de la matriz como variable constante no está permitido en C pero está permitido en C++?

7 minutos de lectura

avatar de usuario
Kadina

¿Intenté escribir un programa de CA como se muestra a continuación?

const int x = 5;

int main()
{
    int arr[x] = {1, 2, 3, 4, 5};
}

Esto está dando advertencias cuando traté de compilar con gcc como se muestra a continuación.

simple.c:9: error: no se puede inicializar el objeto de tamaño variable.

Pero lo mismo está permitido en C++. Cuando paso x como tamaño de matriz, ¿por qué x no se trata como constante?

  • Porque los diseñadores de C decidieron que no debería ser tratado como constante

    –MM

    18 de septiembre de 2014 a las 0:50

  • Los diseñadores de lenguajes pueden especificar lo que está bien y lo que está mal. C no es solo un subconjunto de C++. Los dos idiomas son distintos. La regla de C simplifica un poco el trabajo del compilador. Esa es la razón probable de la diferencia, pero es solo una suposición.

    – Gen

    18 de septiembre de 2014 a las 0:51


  • @MattMcNabb punto justo, agregó detalles relevantes que también explican eso.

    – Shafik Yaghmour

    18 de septiembre de 2014 a las 1:49

avatar de usuario
keith thompson

const no significa “constante” (es decir, evaluable en tiempo de compilación). simplemente significa solo lectura.

Por ejemplo, dentro de una función, esto:

const int r = rand();
const time_t now = time(NULL);

es perfectamente valido.

El nombre de un objeto definido como const int no es un expresión constante. Eso significa que (en C antes de C99 y en todas las versiones de C++) no se puede usar para definir la longitud de una matriz.

Aunque C99 (y, opcionalmente, C11) admiten matrices de longitud variable (VLA), no se pueden inicializar. En principio, el compilador no conoce el tamaño de un VLA cuando se define, por lo que no puede verificar si un inicializador es válido. En su caso particular, es muy probable que el compilador pueda resolverlo, pero las reglas del lenguaje están diseñadas para cubrir el caso más general.

C++ es cerca de lo mismo, pero C++ tiene una regla especial de la que C carece: si un objeto se define como consty su inicialización es una expresión constante, entonces el nombre del objeto en sí mismo es una expresión constante (al menos para tipos integrales).

No hay ninguna buena razón por la que C no haya adoptado esta característica. En C, si desea una constante de nombre de tipo entero, el enfoque habitual es utilizar una macro:

 #define LEN 5
 ...
 int arr[LEN] = {1, 2, 3, 4, 5};

Tenga en cuenta que si cambia el valor de LENtendrás que volver a escribir el inicializador.

Otro enfoque es utilizar un anónimo enum:

 enum { LEN = 5 };
 ...
 int arr[LEN] = {1, 2, 3, 4, 5};

El nombre de una constante de enumeración es en realidad una expresión constante. En C, por razones históricas, siempre es de tipo int; en C++ es del tipo de enumeración. Desafortunadamente, este truco solo funciona para constantes de tipo intpor lo que está restringido a valores en el rango de INT_MIN para INT_MAX.

  • “si un objeto se define como const, y su inicialización es una expresión constante, entonces el nombre del objeto en sí mismo es una expresión constante”. No creo que esto sea correcto. Ver: stackoverflow.com/a/13347355/866732

    – WiSaGaN

    18 de septiembre de 2014 a las 1:10

  • @WiSaGaN: creo que se aplica al menos a los tipos integrales. Un experimento rápido muestra que dado const int five = 5;Puedo usar case five: en una declaración de cambio (usando g ++ 4.8.2 con -pedantic y un montón de avisos habilitados). No estoy seguro de las reglas para el punto flotante. He actualizado mi respuesta para referirme a tipos integrales.

    –Keith Thompson

    18 de septiembre de 2014 a las 1:14


Cuando paso x como tamaño de matriz, ¿por qué x no se trata como constante?

Porque en C, las expresiones constantes no pueden involucrar los valores de ninguna variable, incluso const unos. (Esta es una de las razones por las que C depende tanto de las macro constantes, mientras que C++ usaría const variables para el mismo propósito.)

Por otro lado, en C++, x sería ciertamente una expresión constante si x se declara como const int x = 5;.

Si tu pregunta es por qué C ++ es mucho más liberal que C cuando se trata de expresiones constantes, creo que es compatible con la metaprogramación y permite realizar cálculos complejos en tiempo de compilación utilizando plantillas.

avatar de usuario
Shafik Yaghmour

Creo que casi todos han entendido mal el error, el error dice:

el objeto de tamaño variable no se puede inicializar.

que es correcto, C99 y C11(aunque son opcionales en C11). No se pueden inicializar en la declaración, podemos ver esto en la sección 6.7.8 Inicialización:

Se trata como un VLA porque, a diferencia de C++, C espera un expresión constante entera:

Si el tamaño es una expresión constante entera y el tipo de elemento tiene un tamaño constante conocido, el tipo de matriz no es un tipo de matriz de longitud variable;

y una expresión constante entera tiene las siguientes restricciones:

tendrá un tipo entero y solo tendrá operandos que sean constantes enteras, constantes de enumeración, constantes de caracteres, expresiones de tamaño cuyos resultados sean constantes enteras y constantes flotantes que sean los operandos inmediatos de las conversiones. Los operadores de conversión en una expresión constante entera solo convertirán tipos aritméticos en tipos enteros, excepto como parte de un operando en el operador sizeof.

cual x no satisface.

El tipo de entidad que se va a inicializar será una matriz de tamaño desconocido o un tipo de objeto que no sea un tipo de matriz de longitud variable.

En C ++, esta no es una matriz de longitud variable ya que x se considera un expresión constante y podemos que esto sea válido desde el borrador de la sección estándar de C++ 8.3.4 arreglos en la sección 8 declarantes que dice:

En una declaración TD donde D tiene la forma

 D1 [ constant-expressionopt] attribute-specifier-seqopt

[…]Si la expresión-constante (5.19) está presente, será una expresión constante convertida de tipo std::size_t y su valor será mayor que cero. La expresión constante especifica el límite de (número de elementos en) la matriz. Si el valor de la expresión constante es N, la matriz tiene N elementos numerados de 0 a N-1[…]

Si quitamos el constante de la declaración de x fallaría por una de dos razones, el compilador admite VLA como extensión y fallaría por la misma razón que falla en C o el compilador no admite VLA como extensión y, por lo tanto, la declaración no sería válida.

  • No todo el mundo; Lo mencioné en mi respuesta. Y gran parte del problema es por qué arr está siendo tratado como un objeto de tamaño variable.

    –Keith Thompson

    18 de septiembre de 2014 a las 1:16


  • @KeithThompson oh sí, ahora veo que tus respuestas comienzan como las de todos los demás, así que me perdí eso.

    – Shafik Yaghmour

    18 de septiembre de 2014 a las 1:21

Asumiré que está utilizando un compilador C99 (que admite matrices de tamaño dinámico). Lo que sucede es que el compilador no puede saber con certeza en tiempo de compilación cómo se comportará su matriz con respecto a la memoria.

Prueba esto:

int arr[x];
memset( arr, 0, x*sizeof(int) );

y ver si funciona.

Otra cosa que creo que podría estar causando esto es que const realmente no significa nada debajo del capó, por lo que es posible que el compilador no le permita hacer lo que está tratando de hacer por eso. Verá, hay varias formas de modificar las variables const, y eso es parte de por qué c#, por ejemplo, no presenta la palabra clave const. const es más como una alerta para los humanos que cualquier otra cosa.

¿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