Trying to trace a char [] prints "true"
class Main {
static function main() {
untyped __cpp__('char testVariable[] = "hello" ');
untyped trace(testVariable);
}
}
should output hello but outputs true instead
this warning points to the main issue.
./src/Main.cpp:34:38: warning: address of array 'testVariable' will always evaluate to 'true' [-Wpointer-bool-conversion] th
You can use something like
untyped __cpp__('char testVariable[] = "hello" ');
var s : String = "";
untyped __cpp__('s = testVariable;');
trace(s);
but I'm not sure about this code. Main recommendation - avoid untyped code
but I'm not sure about this code. Main recommendation - avoid untyped code
I was just doing that as an example
The real place where this comes into an issue is externs that use char[]
this warning points to the main issue.
./src/Main.cpp:34:38: warning: address of array 'testVariable' will always evaluate to 'true' [-Wpointer-bool-conversion]
Im not getting this warning when compiling
Trace works on Dynamic, so the object you're trying to trace needs to be convertable to Dynamic. char[] is not. However, bool is, so the c/c++ pointer to bool conversion implicitly occurs.
I will second the recommendation of avoiding untyped code, if you find yourself reaching for it it's a good indicator you're doing something wrong. It would be better if you posted the code you're trying to extern so people can give suggestions of what to do instead.
It would be better if you posted the code you're trying to extern so people can give suggestions of what to do instead.
struct toml_result_t {
bool ok; // success flag
toml_datum_t toptab; // valid if ok
char errmsg[200]; // valid if not ok
void *__internal; // do not use
};
I will second the recommendation of avoiding untyped code, if you find yourself reaching for it it's a good indicator you're doing something wrong.
I was just doing that for the example since I wasn't sure if there was a way to compile a native char[] with haxe
What you could do is something like this.
On the haxe side your externs would look like this, the abstract which only exposes standard haxe types is what the user interacts with, no pointers or anything leaked.
// All your usual extern meta
@:native('toml_result_t')
private extern class TomlResultImpl {
@:native('::hxcpp_toml::get_ok')
public static function get_ok(p:TomlResultPointer):Bool;
@:native('::hxcpp_toml::get_error')
public static function get_error(p:TomlResultPointer):String;
}
private typedef TomlResultPointer = cpp.Star<TomlResultImpl>;
abstract TomlResult(TomlResultPointer) {
public var ok (get, never) : Bool;
function get_ok() {
return TomlResultImpl.get_ok(this);
}
public var error (get, never) : String;
function get_error() {
return TomlResultImpl.get_error(this);
}
}
and you can have some very basic c++ wrappers to conver the native types into haxe friendly ones.
namespace hxcpp_toml
{
bool get_ok(toml_result_t* ptr)
{
return ptr->ok;
}
::String get_error(toml_result_t* ptr)
{
return ::String::create(ptr->errmsg, 200);
}
}
If you setup the build xml correctly you could build those wrappers as an independent library, reducing build times and allowing those cached builds to be re-used between projects. Win win all around.
Only a partial example and all untested / just off the top of my head. But should give you an idea of a better approach.
I was able to add a workaround by declaring the char[] as an abstract
extern abstract ForcedString(String) to (String) {
inline function new(s:String)
this = untyped __cpp__("::String( {0} )", s);
@:from
static public inline function fromString(s:String):ForcedString
return new ForcedString(s);
@:to extern public inline function toString():String
return new String(untyped this);
}
And while this does work I do think it would be good to get it supported properly on hxcpp
The problem is that char* (what char[] decays to) is ambiguous. You seem to want a char* to Dynamic conversion to convert it to a string inbetween, and that might make sense for that specific instance, char* is also extremely common for representing byte buffers. In that case converting it to a string make no sense and depending on the size of the buffer could cause large memory spikes as hxcpp copies strings into gc memory. The c type system is full of ambiguities like this which is why hxcpp lacks many conversions.
While it seems like it's falling on deaf ears it bares repeating a third time for anyone else coming across this issue, please don't use untyped like that. Untyped leads to extremely brittle code which you will end up paying for down the line.
While it seems like it's falling on deaf ears it bares repeating a third time for anyone else coming across this issue, please don't use untyped like that. Untyped leads to extremely brittle code which you will end up paying for down the line. Again, I'm not using untyped like that normally, I was only using it in the example code snippet because I do not know of a way to declare that sort of c type using only haxe.
The workaround you posted involved more untyped though?
I do not know of a way to declare that sort of c type using only haxe
That's because you probably shouldn't be trying to do that. Many c types are extremely difficult if not impossible to reasonably represent in haxe, the best thing to do is not even attempt to expose the raw c types to haxe. Instead, as showed in the previous comment, write wrapper c++ functions which convert the c types into something haxe can consume.
I was able to add a workaround by declaring the char[] as an abstract
cpp.ConstCharStar exists for this type of thing, and it is an abstract with the toString conversion similar to what you implemented.
If your native code has something like:
char errmsg[200] = "hello";
You can have haxe code like this:
@:include("native.h")
extern class Extern {
@:native("errmsg")
static final errmsg:cpp.ConstCharStar;
}
function main() {
trace(Extern.errmsg);
}
Then it gets converted to a haxe string automatically.