Различные результаты между 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 56

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 для прямой инициализации.