4 ms·
> Does modern C++ have a better solution to implement the same thing? I'm no guru, but I know from experience you can do it in C++: {0}[calvin ~] cat test.c
by jcalvinowens 4y ago
> Does modern C++ have a better solution to implement the same thing?
I'm no guru, but I know from experience you can do it in C++:
{0}[calvin ~] cat test.cpp
#include <iostream>
#include <memory>
struct foo {
int len;
int v[];
};
int main(void) {
auto p = std::unique_ptr<foo>(reinterpret_cast<struct foo *>(
malloc(sizeof(struct foo) + sizeof(int) * 2)));
p->v[1] = 99;
std::cerr << p->v[1] << std::endl;
return 0;
}
{0}[calvin ~] g++ -Wall -Wextra -std=c++17 test.cpp -o test
{0}[calvin ~] ./test
99
{0}[calvin ~] clang++ -Wall -Wextra -std=c++17 test.cpp -o test
{0}[calvin ~] ./test
99
EDIT: Remove unnecessary extern block, as pointed out by wahern in the replies.
- loeg 4y agoYes, you can do this in C++, but keep in mind that implicitly generated copy/move constructors don't understand this and will not copy the full object. This can produce surprising memory corruption that can be difficult to debug. So you should be sure to either explicitly mark the struct not copy/movable, or implement smarter copy/move operators.
- _gabe_ 4y agoTbf I don't think C copies the whole flexible array member either[0]. So the care you would normally take while using a flexible array member in C should also be taken in C++ :) [0]: https://stackoverflow.com/questions/35423293/flexible-array-member-not-getting-copied-when-i-make-a-shallow-copy-of-a-struct https://stackoverflow.com/questions/35423293/flexible-array-...
- loeg 4y agoRight. But C has fewer scenarios where implicit copies are possible, in part because it does not have references.
- wahern 4y agoFlexible array members are commonly supported as an extension in C++ compilers, but the C++ standard itself does not permit them. And FWIW `extern "C"` doesn't drop a C++ compiler into a "C mode", it merely effects linkage (i.e. name mangling); all the code within the scope must still be valid, compiler-supported C++. Your example code compiles the same without the extern "C" declaration. And it compiles the same if main is also placed within the extern "C" scope; but not the headers, as C++ constructs like templates cannot have C linkage.
- jcalvinowens 4y agoD'oh, thanks for pointing that out.
- masklinn 4y agoUnrelated to the article but since you seem to know this stuff, do you know what happens when a function in an “extern C” block exposes C++ types (parameters or return types)? I assume it’s broken because it’d expect the actual C++ types to be passed in despite the lack of ABI stability, and only the linking / name mangling is affected (possibly calling conventions as well?) but I’m not actually sure.
- codeflo 4y agoC++ types are structs and unions if you get down to the bottom of things. This is possibly not guaranteed by the standard, but AFAIK, extern "C" doesn’t ever affect the calling convention or memory layout for the parameters, only the name mangling for the linker. So in theory, if you manage to construct a valid std::string in C code (which is hard, given its invariants, and would be absolutely nonportable), then you could pass it to an extern "C" function that’s written in C++.
- pjmlp 4y agoYou could that with a function that would map a ptr/len pair into a std::span.
- jenadine 4y agoIt compiles and work doesn't mean it is not undefined behaviour. You should at least try with the ub sanitizer. But in this case, as other said, it may be accepted as an extension. Still not part of C++