Различные результаты между gcc и clang при компиляции довольно простой программы на c++11
Я пытаюсь понять, связано ли различное поведение, выставленное gcc против clang в выводе этой простой программы C++11, с ошибкой в clang (Xcode 5.0.2, OS X 10.8.5). Код выглядит следующим образом:
#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;
}
как показано, я пытаюсь использовать равномерную инициализацию для инициализации анонимного (ОТВ. именованный) многомерный массив размера 3x3
. При компиляции с gcc 4.7 из MacPorts получается ожидаемый результат:
$g++-mp-4.7 -std=c++11 dyn_matrix.cpp -o dyn_matrix
$ ./dyn_matrix
2
2
$
наоборот, в случае clang используется выход читает:
$ clang++ -std=c++11 -stdlib=libc++ dyn_matrix.cpp -o dyn_matrix_clang
$ ./dyn_matrix_clang
2
4
$
в этом случае результат (видимо) неправильно. clang --version
отчеты:
Apple LLVM version 5.0 (clang-500.2.75) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin12.5.0
Thread model: posix
кто виноват? я, gcc или clang?
обновление 11 декабря 2013: ошибка должна была быть исправлена в r196995. К сожалению, мы все еще не знаем, сколько времени потребуется, прежде чем Apple обновит версию clang, которая поставляется с Xcode.
обновление 9 декабря 2013: я отправил отчет об ошибке на Платформа LLVM bugzilla. Это действительно было признано ошибкой, патч в настоящее время рассматривается, см. http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20131209/095099.html.
спасибо.
1 ответ:
обновление: благодаря Фейсалу Вали и Ричарду Смиту, эта ошибка была исправлена в Clang ToT; см. тестовый файл введена фиксация.
по данным §8.5.1 [dcl.в этом.примечанияа] похоже, что Clang ошибается:
11 / фигурные скобки могут быть удалены в инициализатор-список следующим образом. Если инициализатор-список начинается с левой фигурной скобки, то последующий разделенный запятыми список инициализатор-п. инициализирует членов подагрегата; это ошибочно, чтобы было больше инициализатор-п. чем члены. Если, однако,инициализатор-список для подагрегата не начинается с левой скобки, то только достаточно инициализатор-п. из списка берутся для инициализации члены субагрегата; любые оставшиеся инициализатор-п. осталось инициализируйте следующий элемент агрегата, членом которого является текущий субагрегат. [ пример:
float y[4][3] = { { 1, 3, 5 }, { 2, 4, 6 }, { 3, 5, 7 }, };
- это полностью связанная инициализация: 1, 3 и 5 инициализируют первую строку массива
y[0]
, а именноy[0][0]
,y[0][1]
иy[0][2]
. Аналогично, следующие две строки инициализируютy[1]
иy[2]
. Инициализатор заканчивается рано и поэтомуy[3]
s элементы инициализируются так, как если бы они были явно инициализированы выражением видаfloat()
, то есть, инициализируются с0.0
. В следующем примере скобки инициализатор-список сокращаются, однако инициализатор-список имеет тот же эффект, что и полностью собранный инициализатор-список из приведенного выше примера,float y[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 };
инициализатор для y начинается с левой фигурной скобки, но один для
y[0]
нет, поэтому используются три элемента из списка. Аналогично следующие три взяты последовательно ибоy[1]
иy[2]
. - пример]который, я думаю, применяется из-за §5.3.4 [expr.новое]:
15/ A new-expression создает объект типа T инициализирует этот объект следующим образом:
- если new-initializer опущен, объект по умолчанию инициализируется (§8.5); если инициализация не выполняется, объект неопределенное значение.
- иначе new-initializer интерпретируется в соответствии с правилами инициализации §8.5 для прямой инициализации.