I'm trying to understand whether the different behavior exposed by gcc vs. clang in the output of this simple C++11 program is due to a bug in clang (Xcode 5.0.2, OS X 10.8.5). The code is as follows:
#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; }
As shown, I'm trying to use uniform initialization to initialize an anonymous (resp. named) multidimensional array of size 3x3
. When compiling with gcc 4.7 from MacPorts the expected output is obtained:
$g++-mp-4.7 -std=c++11 dyn_matrix.cpp -o dyn_matrix $ ./dyn_matrix 2 2 $
Conversely, in case clang is used the output reads:
$ clang++ -std=c++11 -stdlib=libc++ dyn_matrix.cpp -o dyn_matrix_clang $ ./dyn_matrix_clang 2 4 $
In this case the result is (apparently) wrong. clang --version
reports:
Apple LLVM version 5.0 (clang-500.2.75) (based on LLVM 3.3svn) Target: x86_64-apple-darwin12.5.0 Thread model: posix
Who's to blame? me, gcc or clang?
UPDATE Dec 11th, 2013: The bug should have been fixed in r196995. Unfortunately, we still do not know how long it will take before Apple updates the version of clang that ships with Xcode.
UPDATE Dec 9th, 2013: I submitted a bug report on the LLVM bugzilla platform. It has indeed been recognized as a bug, a patch is currently under review, see http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20131209/095099.html.
Thanks.
Clang is designed as an API from its inception, allowing it to be reused by source analysis tools, refactoring, IDEs (etc) as well as for code generation. GCC is built as a monolithic static compiler, which makes it extremely difficult to use as an API and integrate into other tools.
TL;DR: Clang is highly compatible to GCC - just give it a go. In most cases, Clang could be used as a GCC drop in replacement ( clang and clang++ are "GCC compatible drivers").
If you want to use clang instead of GCC, you can add -DCMAKE_C_COMPILER=/path/to/clang -DCMAKE_CXX_COMPILER=/path/to/clang++ . You can also use ccmake , which provides a curses interface to configure CMake variables in an interactive manner.
To activate C++11, you have to add -std=c++11 in your clang calls, like for gcc. If you use an IDE that is clang-aware or gcc-aware, there is a specific project settings option available to do that.
Update: Thanks to Faisal Vali and Richard Smith, this bug has been corrected in Clang ToT; see the test file introduced by the commit.
According to §8.5.1 [dcl.init.aggr] it appears that Clang is wrong:
11/ Braces can be elided in an initializer-list as follows. If the initializer-list begins with a left brace, then the succeeding comma-separated list of initializer-clauses initializes the members of a subaggregate; it is erroneous for there to be more initializer-clauses than members. If, however, the initializer-list for a subaggregate does not begin with a left brace, then only enough initializer-clauses from the list are taken to initialize the members of the subaggregate; any remaining initializer-clauses are left to initialize the next member of the aggregate of which the current subaggregate is a member. [ Example:
float y[4][3] = { { 1, 3, 5 }, { 2, 4, 6 }, { 3, 5, 7 }, };
is a completely-braced initialization: 1, 3, and 5 initialize the first row of the array
y[0]
, namelyy[0][0]
,y[0][1]
, andy[0][2]
. Likewise the next two lines initializey[1]
andy[2]
. The initializer ends early and thereforey[3]
s elements are initialized as if explicitly initialized with an expression of the formfloat()
, that is, are initialized with0.0
. In the following example, braces in the initializer-list are elided; however the initializer-list has the same effect as the completely-braced initializer-list of the above example,float y[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 };
The initializer for y begins with a left brace, but the one for
y[0]
does not, therefore three elements from the list are used. Likewise the next three are taken successively fory[1]
andy[2]
. —end example ]
Which I think applies because of §5.3.4 [expr.new]:
15/ A new-expression that creates an object of type T initializes that object as follows:
- If the new-initializer is omitted, the object is default-initialized (§8.5); if no initialization is performed, the object has indeterminate value.
- Otherwise, the new-initializer is interpreted according to the initialization rules of §8.5 for direct initialization.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With