Array como compuesto literal

En C99 podemos usar literales compuestos como una matriz sin nombre.

Pero son estas constantes literales como por ejemplo 100 , 'c' , 123.4f , etc.

Me di cuenta de que puedo hacer:

 ((int []) {1,2,3})[0] = 100; 

y, no tengo ningún error de comstackción y es probable que el primer elemento de esa matriz sin nombre se modifique con 100.

Así que parece que la matriz como literal compuesto es lvalue y no valor constante.

Es un valor, podemos ver esto si nos fijamos en el borrador de la sección C99, sección 6.5.2.5 compuestos que dice ( énfasis mío ):

Si el nombre de tipo especifica una matriz de tamaño desconocido, el tamaño se determina por la lista de inicializadores como se especifica en 6.7.8, y el tipo del literal compuesto es el del tipo de matriz completado. De lo contrario (cuando el nombre del tipo especifica un tipo de objeto), el tipo del literal compuesto es el especificado por el nombre del tipo. En cualquier caso, el resultado es un valor l.

Si desea una versión de const , más adelante en la misma sección se muestra el siguiente ejemplo:

EJEMPLO 4 Un literal compuesto de solo lectura puede especificarse a través de construcciones como:

 (const float []){1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6} 

Podemos encontrar una explicación de la terminología en este artículo del Dr. Dobb The New C: Compound Literals y dice:

Los literales compuestos no son constantes verdaderas porque el valor del literal podría cambiar, como se muestra más adelante. Esto nos lleva a un poco de terminología. Los Estándares C99 y C90 [2, 3] usan la palabra “constante” para tokens que representan valores verdaderamente inmutables que son imposibles de modificar en el idioma. Por lo tanto, 10 y 3.14 son una constante decimal entera y una constante flotante de tipo doble, respectivamente. La palabra “literal” se utiliza para la representación de un valor que puede no ser tan constante. Por ejemplo, las primeras implementaciones de C permitieron modificar los valores de las cadenas entre comillas. C90 y C99 prohibieron la práctica diciendo que cualquier progtwig que modificara un literal de cadena tenía un comportamiento indefinido, que es la forma estándar de decir que podría funcionar, o que el progtwig podría fallar de una manera misteriosa. […]

Por lo que recuerdo que tienes razón, los literales compuestos son lvalues ​​*, también puedes tomar el puntero de ese literal (que apunta a su primer elemento):

 int *p = (int []){1, 2, 3}; *p = 5; /* modified first element */ 

También es posible aplicar el calificador const en dicho literal compuesto, por lo que los elementos son de solo lectura:

 const int *p = (const int []){1, 2, 3}; *p = 5; /* wrong, violation of `const` qualifier */ 

* Tenga en cuenta que esto no significa que sea un lvalue modificable automáticamente (por lo que se puede usar como operando izquierdo para el operador de asignación), ya que tiene un tipo de matriz y se refiere al borrador C.2 6.3.2.1 .

Un lvalue modificable es un lvalue que no tiene tipo de matriz, […]

Refiriéndose al proyecto de norma C11 N1570 :

Sección 6.5.2.5p4:

En cualquier caso, el resultado es un valor l.

Un “lvalue” es, aproximadamente, una expresión que designa un objeto, pero es importante tener en cuenta que no todos los lvalues ​​son modificables. Un ejemplo simple:

 const int x = 42; 

El nombre x es un lvalor, pero no es un lvalor modificable. (Las expresiones del tipo de matriz no pueden ser valores de valores modificables, porque no se pueden asignar a un objeto de matriz, pero los elementos de una matriz pueden ser modificables).

Párrafo 5 de la misma sección:

El valor del literal compuesto es el de un objeto sin nombre inicializado por la lista de inicializadores. Si el literal compuesto ocurre fuera del cuerpo de una función, el objeto tiene una duración de almacenamiento estático; de lo contrario, tiene una duración de almacenamiento automático asociada con el bloque adjunto.

La sección que describe literales compuestos no dice específicamente si el objeto sin nombre es modificable o no. En ausencia de tal statement, se considera que el objeto es modificable a menos que el tipo esté constamente calificado.

El ejemplo en la pregunta:

 ((int []) {1,2,3})[0] = 100; 

no es particularmente útil, ya que no hay manera de referirse al objeto sin nombre después de la asignación. Pero una construcción similar puede ser bastante útil. Un ejemplo artificial:

 #include  int main(void) { int *ptr = (int[]){1, 2, 3}; ptr[0] = 100; printf("%d %d %d\n", ptr[0], ptr[1], ptr[2]); } 

Como se mencionó anteriormente, la matriz tiene una duración de almacenamiento automático, lo que significa que si se crea dentro de una función, dejará de existir cuando la función regrese. Los literales compuestos no son un reemplazo para malloc .

Los literales compuestos son valores y sus elementos pueden ser modificables. Puedes asignarle un valor. Incluso se permiten punteros a literales compuestos.