3

I got C-Code that already exists and that makes use of C99-style VLAs. Like this one:

 int foo(int n, double l[n][n], double a[n][n]);

I'd like to include the headers in my C++11 project. As C++ doesn't allow these kind of constructs I'm using extern "C" to include these header files. However the compiler doesn't like this at all.

./header.h:23:42: error: use of parameter outside function body before ‘]’ token
 void foo(int n, double l[n][n], double x[n], double b[n]);
                           ^
./header.h:23:45: error: use of parameter outside function body before ‘]’ token
 void foo(int n, double l[n][n], double x[n], double b[n]);
                              ^
./header.h:23:46: error: expected ‘)’ before ‘,’ token
 void foo(int n, double l[n][n], double x[n], double b[n]);
                               ^
./header.h:23:48: error: expected unqualified-id before ‘double’
 void foo(int n, double l[n][n], double x[n], double b[n]);
                                 ^~~~~~

I think I read somewhere that VLAs became optional in C11. Does this mean that gcc got rid of it completely? If so what can I do other than extern "C"? Of course I can compile the source with an older C-standard. But I have to include the headers somehow. Any idea?

Rewriting the whole thing would only be a method of last resort.

Lundin
  • 195,001
  • 40
  • 254
  • 396
Scindix
  • 1,254
  • 2
  • 15
  • 32
  • You do not have any alternative to compiling your source with a C compiler, as C++ does not have variable-length arrays. I think the variable-length array is passed as a pointer to the first element, anyway. Hence if you declare your last function as `extern "C" { void foo(int n, double * l, double * x, double * b); }` in your C++ code, it should be called correctly. (That's, however, only a guess.) – JohnB Jun 28 '16 at 20:25
  • You're probably wanting to use `--std=gnu++14` which enables C++14 features, rather than `--std==c++14` which enables C++14 features **and disables all g++ extensions** – Ben Voigt Jun 28 '16 at 20:38
  • VLAs are invalid in standard C++, and optional in C from C11. Whether they are supported in C or not, it is better to avoid trying to use them in C++. You will need to write an `extern "C"` wrapper function that provides an interface acceptable to C++, and passes (or copies) its arguments on to your function that uses VLAs. That wrapper will need to be implemented (and therefore compiled) as C, but it is essential it provides a signature (return type and argument types) that is valid C++. Personally, I'd rewrite the function as C++, and be done with it. – Peter Jun 28 '16 at 21:00
  • gcc continues to support VLAs in C code in C11 mode (`-std=c11`); it does not define the macro `__STDC_NO_VLA__`. (This says nothing about C++ code.) – Keith Thompson Jun 28 '16 at 21:25
  • VLAs never were a part of C++, and `extern "C"` doesn't magically make them so, regardless of version (just stating the obvious here). – n. m. could be an AI Jun 30 '16 at 08:19
  • So I guess the question here is really: Are VLAs part of gnu++14? In that case, that sounds like the best work-around. A far less pretty work-around would be to compile part of the source as C++ and other parts as C, then write wrapper functions around all C features that C++ does not support. – Lundin Jun 30 '16 at 11:35

1 Answers1

3

I'd like to include the headers in my C++11 project. As C++ doesn't allow these kind of constructs I'm using extern "C" to include these header files. However the compiler doesn't like this at all.

Indeed, this is a problem, as C++11 doesn't have VLAs. You might want to consider writing a wrapper in C, compiling that as C and using it in C++.


I think I read somewhere that VLAs became optional in C11. Does this mean that gcc got rid of it completely?

No, gcc still supports VLAs when compiling code as C11. However, that's irrelevant to your question, which is about C++11, a completely different language, which has no support for VLAs.


what can I do other than extern "C"?

extern "C" alone won't help you, because as I explained C++11 doesn't have VLAs. Consider that in C, an array is a contiguous sequence, meaning it's all one allocation and all elements occur one after the other. Hence, such a two-dimensional array is represented flattened as a one-dimensional array of n * n elements. Your wrapper, also using extern "C", should translate a double * pointing to the first element of that flattened array to a double (*)[n] pointing to the first n elements of that flattened array.

That's a typecast in C11, which doesn't need to be exposed to C++ because the function that takes a double *, the function is compiled as C11 code (not C++11) and linked to the C++11 project using the linker. C++11 doesn't need to see the C11 code underneath the function.

So you'll need to rewrite the header (which you could maintain independently from the .h file as a .hpp file), which thankfully isn't a complete rewrite. At least hopefully you've learnt, C++ isn't a strict superset of C.

autistic
  • 1
  • 3
  • 35
  • 80