aardvarkk
aardvarkk

Reputation: 15996

C++ variable length array on the stack

I've just encountered code in the project dcraw that's causing the Visual Studio 2012 compiler to fail. It's of the following form:

void CLASS cubic_spline (const int *x_, const int *y_, const int len)
{
  float A[2*len][2*len], b[2*len], c[2*len], d[2*len];
  ...

The problem is the creation of these variable length arrays on the stack. I've never really seen code like this -- is it possible to compile this in the Visual Studio compiler?

Upvotes: 2

Views: 257

Answers (3)

Matthieu M.
Matthieu M.

Reputation: 300439

As mentioned, VLA (Variable-Length Arrays) are a C feature, and more to the point a C99 feature which Visual Studio does not support. On Linux, Clang and Gcc both support C99 (and C11 I believe) and allow this syntax in C++ as an extension.

In C++, you can easily transform the code by switching to std::vector<float> for all simple arrays. Only A will require a bit more work:

  • you can either use a std::vector< std::vector<float> >, but then you lose contiguity and locality
  • or you can use a flattened version std::vector<float> A(2*len*2*len); but then you will lose access by A[i][j] which will have to be transformed into A[i*2*len + j] instead

In any case, you will need to update this code to make it work on Visual Studio.

EDIT: per your comment:

The function is called twice in the code, once as cubic_spline(cx, cf, 9); and once as cubic_spline(cx, cf, 18);. In the first example, cx and cy are int[9] and in the second example they're int[18].

In this case you can actually make the function a template:

template <size_t len>
void CLASS cubic_spline(int const (&x)[len], int const (&y)[len]) {
    float A[2*len][2*len], b[2*len], c[2*len], d[2*len];
}

Note that I removed the last parameter, because it is no longer necessary. The type of x and y is int const (&)[len] which is a reference to an array of int const of length len.

Upvotes: 2

Shoe
Shoe

Reputation: 76308

There are working compiler extensions (such as Clang's one and GCC's one) that allow this, but it's not standard, yet.

In C++11 you can also use constexpr if the numeric value is constant. And finally a proposal has been submitted to standardize it.

If x_ and y_ are meant to be arrays, you can just use std::array as follows:

template<std::size_t size>
void CLASS cubic_spline (std::array<int, size> const& x, std::array<int, size> const& y)
{
    using float_array = std::array<float, 2 * size>;
    std::array<float_array, 2 * size> A;
    float_array b, c, d;
    // ...
}

This way you could ensure that the passed arrays dimensions are equal, at compile time.

Otherwise you can clean that up with std::vector:

void CLASS cubic_spline (std::vector<int> const& x, std::vector<int> const& y)
{
    std::vector<std::vector<float>> A(2 * x.size());
    std::vector<float> b, c, d;
    // ...
}

Upvotes: 2

Christian Hackl
Christian Hackl

Reputation: 27548

This is a GCC-specific compiler extension, see Arrays of Variable Length. I am not aware of any compiler options to make them work out of the box in VC. If this is a very isolated problem, try preprocessor #ifdefs to serve different code to VC.

Upvotes: 1

Related Questions