V version: 0.1.26/master
OS: Linux test 4.15.0-96-generic #97-Ubuntu SMP Wed Apr 1 03:25:46 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
What did you do?
VFLAGS="-cc c++" v -cflags '-c -pipe -O3 -W -Wall -Wpointer-arith -Wno-unused-parameter -w -fpermissive -std=gnu++17' -g -show_c_cmd vweb.v
vweb is a custom version of a server which calls out extern c functions exposed from a c++ library
What did you expect to see?
The code should compile correctly even with a c++ compiler
What did you see instead?
==================
/root/.cache/v/vweb.tmp.c: In function ‘int strings__levenshtein_distance(string, string)’:
/root/.cache/v/vweb.tmp.c:1557:79: error: taking address of temporary array
array_int f = array_repeat(new_array_from_c_array(1, 1, sizeof(int), (int[1]){
^
0,
~~
}), b.len + 1);
~
/root/.cache/v/vweb.tmp.c: In function ‘string strconv__ftoa__Dec32_get_string_32(strconv__ftoa__Dec32, bool, int, int)’:
/root/.cache/v/vweb.tmp.c:2031:84: error: taking address of temporary array
array_byte buf = array_repeat(new_array_from_c_array(1, 1, sizeof(byte), (byte[1]){
^
...
==================
This needs a fix in https://github.com/vlang/vc (v.c)
It is a common misconception that C++ is a superset of C. There are features in modern C that do not work in C++ - and addresses of temporary arrays is one of them. Try this C program:
#include <stdio.h>
void print_arr(int x[], int len) {
for (int i = 0; i<len; i++) {
printf("%d\n", x[i]);
}
}
int main() {
print_arr((int[]){1, 2, 3}, 3);
}
This program works when compiled with a C compiler, but a C++ compiler complains about taking the address of a temporary array.
In C++ you can accomplish similar things by using new(or better std::make_unique). However, whereas the C variant stores the temporary array on the stack, the C++ counterpart stores it on the heap i.e. the memory has to be freed afterwards (that's what smart pointers do automatically).
To make a long story short: C and C++ are different languages. you can't just take C code and compile it with a C++ compiler.
Passing addresses of temporary arrays is used all over the place in generated C.
These are indeed two very different languages, so I think it's best to use 2 different compilers for C and C generated by V, and C++.
It would definitely be nice to make generated C compilable with g++ for simpler integration into a C++ code base, but I'm not sure it's possible.
You can put it on the agenda for a 2.0 or 3.0 release... ;-)
Maybe it could be done with some macros and helper functions but I don't think it's worth it. Particularly because as soon as we say "C++ is supported" expectations will come up that aren't fulfilled.
For the distant future it might be more appropriate to have a C++ output engine that makes use of modern C++ features:
string, array, map to STL's std::vector, std::array, std::mapstd::optional for v's optionalstd::uniqe_ptr, std::shared_ptr, std::weak_ptr for automatic memory managementBy making use of these C++ standard features it would be possible to call functions from modern C++-libraries that expect their parameters as STL-conforming objects.
However I think that is a completely new project that takes a lot of time. For now it may be the best to say that currently C++ is officially not supported.
Just for the record: There seems to be a way to pass the address of a temporary array in C++ (and thus solve this particular issue): std::move(). In Rust's terms it performs something like transfer of ownership. The above example program can be modified to compile both as C and C++:
#include <stdio.h>
#ifdef __cplusplus
# include <utility>
# define _MOV std::move
#else
# define _MOV
#endif
void print_arr(int x[], int len) {
for (int i = 0; i<len; i++) {
printf("%d\n", x[i]);
}
}
int main() {
print_arr(_MOV((int[]){1, 2, 3}), 3);
}
This program produces the same assembler code when compiled as C and C++ with gcc/g++ 9.3.0 with '-O2'.
What a superb suggestion Uwe, I am so angry at myself for not thinking about that. Lovely solution. Let me change my PR to include this code.
isn't this solved?
Yup this is resolved
Most helpful comment
Just for the record: There seems to be a way to pass the address of a temporary array in C++ (and thus solve this particular issue):
std::move(). In Rust's terms it performs something like transfer of ownership. The above example program can be modified to compile both as C and C++:This program produces the same assembler code when compiled as C and C++ with gcc/g++ 9.3.0 with '-O2'.