Ilio Catallo
Estoy tratando de entender si el comportamiento diferente expuesto por gcc vs. clang en la salida de este programa C++11 simple se debe a un error en clang (Xcode 5.0.2, OS X 10.8.5). El código es el siguiente:
#include <iostream>
int main() {
int matrix[][3]{{1,2,3}, {4,5,6}, {7,8,9}};
auto dyn_matrix = new int[3][3]{{1,2,3}, {4,5,6}, {7,8,9}};
std::cout << matrix[0][1] << std::endl;
std::cout << dyn_matrix[0][1] << std::endl;
return 0;
}
Como se muestra, estoy tratando de usar la inicialización uniforme para inicializar una matriz multidimensional anónima (resp. con nombre) de tamaño 3x3
. Al compilar con gcc 4.7 desde MacPorts se obtiene el resultado esperado:
$g++-mp-4.7 -std=c++11 dyn_matrix.cpp -o dyn_matrix
$ ./dyn_matrix
2
2
$
Por el contrario, en caso de que se use clang, la salida dice:
$ clang++ -std=c++11 -stdlib=libc++ dyn_matrix.cpp -o dyn_matrix_clang
$ ./dyn_matrix_clang
2
4
$
En este caso el resultado es (aparentemente) incorrecto. clang --version
informes:
Apple LLVM version 5.0 (clang-500.2.75) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin12.5.0
Thread model: posix
¿De quien es la culpa? yo, gcc o clang?
ACTUALIZACIÓN 11 de diciembre de 2013: El error debería haberse solucionado en r196995. Desafortunadamente, todavía no sabemos cuánto tiempo pasará antes de que Apple actualice la versión de clang que viene con Xcode.
ACTUALIZACIÓN 9 de diciembre de 2013: Envié un informe de error en la plataforma LLVM bugzilla. De hecho, se ha reconocido como un error, actualmente se está revisando un parche, consulte http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20131209/095099.html.
Gracias.
Matthieu M.
Actualizar: Gracias a Faisal Vali y Richard Smith, este error se ha corregido en Clang ToT; ver el archivo de prueba introducido por el compromiso.
De acuerdo a §8.5.1 [dcl.init.aggr] parece que Clang está equivocado:
11/ Las llaves se pueden elidir en un lista de inicializadores como sigue. Si el lista de inicializadores comienza con una llave izquierda, luego la siguiente lista separada por comas de cláusulas de inicialización inicializa los miembros de un subagregado; es erroneo que haya mas cláusulas de inicialización que los miembros. Si, sin embargo, el lista de inicializadores para un subagregado no comienza con una llave izquierda, entonces solo lo suficiente cláusulas de inicialización de la lista se toman para inicializar los miembros del subagregado; cualquier restante cláusulas de inicialización quedan para inicializar el siguiente miembro del agregado del que es miembro el subagregado actual.[[Ejemplo:
float y[4][3] = { { 1, 3, 5 }, { 2, 4, 6 }, { 3, 5, 7 }, };
es una inicialización completamente reforzada: 1, 3 y 5 inicializan la primera fila de la matriz
y[0]
a sabery[0][0]
,y[0][1]
yy[0][2]
. Del mismo modo, las siguientes dos líneas se inicializany[1]
yy[2]
. El inicializador termina temprano y por lo tantoy[3]
Los elementos s se inicializan como si se inicializaran explícitamente con una expresión de la formafloat()
es decir, se inicializan con0.0
. En el siguiente ejemplo, las llaves en el lista de inicializadores son elididos; sin embargo, el lista de inicializadores tiene el mismo efecto que el completamente arriostrado lista de inicializadores del ejemplo anterior,float y[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 };
El inicializador de y comienza con una llave izquierda, pero el de
y[0]
no lo hace, por lo que se utilizan tres elementos de la lista. Asimismo, los tres siguientes se toman sucesivamente paray[1]
yy[2]
. —ejemplo final ]
Lo cual creo que se aplica debido a §5.3.4 [expr.new]:
15/A nueva expresión que crea un objeto de tipo T inicializa ese objeto de la siguiente manera:
- Si el nuevo inicializador se omite, el objeto se inicializa por defecto (§8.5); si no se realiza ninguna inicialización, el objeto tiene un valor indeterminado.
- De lo contrario, el nuevo inicializador se interpreta de acuerdo con las reglas de inicialización de §8.5 para la inicialización directa.
-
+1 La última oración en tu segunda cita básicamente lo dice. Los inicializadores deben interpretarse de la misma manera (y dado que son idénticos en el fragmento de código, la salida también debe ser idéntica).
– Damon
8 de diciembre de 2013 a las 14:38
-
@Damon: Eso espero, sin embargo, la experiencia pasada dicta que para cada absoluto en el Estándar, hay al menos una excepción escondida en un párrafo no relacionado… sin contar que esto se aplica solo si
{ ... }
es de hecho un nuevo inicializador :/– Matthieu M.
8 de diciembre de 2013 a las 16:25
-
Envié un informe de error en la plataforma LLVM bugzilla. De hecho, se ha reconocido como un error, actualmente se está revisando un parche, consulte lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20131209/…. Editaré la pregunta original para reflejar el cambio.
– Ilio Catallo
9 dic 2013 a las 21:38
-
Al principio no me di cuenta de que ya habías informado que el error se había solucionado. De todos modos, la pregunta principal se ha modificado para reflejar la actualización. Gracias.
– Ilio Catallo
12 de diciembre de 2013 a las 9:36
Visual Studio 2013 dice
2 2
para otra estadística.– Ninja retirado
8 de diciembre de 2013 a las 11:40
+1 por hacer una pregunta buena e interesante. Confirmado que
clang++
v4.2 en OS X 10.7.5 también produce código que genera “2 4”. Mi intuición dice que está mal.– usuario529758
8 de diciembre de 2013 a las 11:41
Hm. La versión de clang que tengo instalada actualmente falla en este código (versión clang 3.4 (tronco 193991)). Es hora de actualizar y ver si eso es mejor…
– Dietmar Kühl
8 de diciembre de 2013 a las 11:56
acabo de probar con
clang 3.4 (trunk 187030)
y puedo confirmar que falla al intentar compilar ese código.– Ilio Catallo
8 de diciembre de 2013 a las 11:57
Aquí hay una demostración en vivo más completa: coliru.stacked-crooked.com/a/4465ae5a4677dc77 . @David
matrix
es unint [3][3]
ydyn_matrix
es unint (*)[3]
asi quesizeof
no ayudará– gx_
8 de diciembre de 2013 a las 12:39