www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Re: struct opCast to void* and back

reply Nrgyzer <nrgyzer gmail.com> writes:
Robert Clipsham Wrote:

 On 11/04/10 10:46, Nrgyzer wrote:
 Hello everyone,

 how can I cast a struct to void* and back to my struct? I have the following
struct:

 struct myStruct {

 	char[] structName;

 	public char[] toString() {
 		return structName;
 	}

 	void* opCast() {
 		return&this;
 	}
 	
 }

 myStruct test = myStruct(); // ok
 test.structName = "Example struct"; // ok
 void* temp = cast(void*) test; // ok
 writefln(cast(myStruct) temp); // failed


 Thanks for solutions&  help :).

Try *cast(MyStruct*). In opCast you are returning &this, which is of type MyStruct* until it is implicitly cast to void*. In the writefln() you then cast it back to MyStruct*, and dereference it so you can use it. In your version you are trying to cast from a pointer to the struct to the actual struct, which is why it doesn't work.

By using *cast(MyStruct*) I get the following message: "Error: 1invalid UTF-8 sequence"
Apr 11 2010
parent reply Robert Clipsham <robert octarineparrot.com> writes:
On 11/04/10 12:47, Nrgyzer wrote:
 Try *cast(MyStruct*). In opCast you are returning&this, which is of
 type MyStruct* until it is implicitly cast to void*. In the writefln()
 you then cast it back to MyStruct*, and dereference it so you can use
 it. In your version you are trying to cast from a pointer to the struct
 to the actual struct, which is why it doesn't work.

By using *cast(MyStruct*) I get the following message: "Error: 1invalid UTF-8 sequence"

I don't know how writefln() works in D1 (I presume that's what you're using), but try the following: writefln( "%s", (*cast(MyStruct*)temp).toString() ); I don't have a D1/Phobos compiler available to me to test, so I don't know if that will help. You usually get that error when trying to print /use strings with invalid UTF sequences in them, which looking at your program, shouldn't be happening. If you're using code other than what you're showing that could be it.
Apr 11 2010
parent reply Nrgyzer <nrgyzer gmail.com> writes:
Robert Clipsham Wrote:

 On 11/04/10 12:47, Nrgyzer wrote:
 Try *cast(MyStruct*). In opCast you are returning&this, which is of
 type MyStruct* until it is implicitly cast to void*. In the writefln()
 you then cast it back to MyStruct*, and dereference it so you can use
 it. In your version you are trying to cast from a pointer to the struct
 to the actual struct, which is why it doesn't work.

By using *cast(MyStruct*) I get the following message: "Error: 1invalid UTF-8 sequence"

I don't know how writefln() works in D1 (I presume that's what you're using), but try the following: writefln( "%s", (*cast(MyStruct*)temp).toString() ); I don't have a D1/Phobos compiler available to me to test, so I don't know if that will help. You usually get that error when trying to print /use strings with invalid UTF sequences in them, which looking at your program, shouldn't be happening. If you're using code other than what you're showing that could be it.

I want to do the following: struct MyStruct { char[] structName; public char[] toString() { return structName; } } ... class MyClass { private static void function(void*) callBack; private static void* callBackValue; ... static this() { MyStruct test = MyStruct(); test.structName = "Struct name"; callBack = &cb; callBackValue = &test; } ... public void cb(void* value) { MyStruct temp = *((cast(MyStruct*) value)); writefln(temp); } }
Apr 11 2010
next sibling parent reply Robert Clipsham <robert octarineparrot.com> writes:
On 11/04/10 15:41, Nrgyzer wrote:
 I want to do the following:

 struct MyStruct {

 	char[] structName;

 	public char[] toString() {

 		return structName;

 	}
 	
 }

 ...

 class MyClass {

 	private static void function(void*) callBack;
 	private static void* callBackValue;
 	...
 	static this() {
 		MyStruct test = MyStruct();
 		test.structName = "Struct name";
 		callBack =&cb;
 		callBackValue =&test;
 	}
 	...
 	public void cb(void* value) {

 		MyStruct temp = *((cast(MyStruct*) value));
 		writefln(temp);

 	}

 }

Why the need for void* everywhere? Surely you could save the effort and store it as a MyStruct?
Apr 11 2010
parent reply Nrgyzer <nrgyzer gmail.com> writes:
Robert Clipsham Wrote:

 On 11/04/10 15:41, Nrgyzer wrote:
 I want to do the following:

 struct MyStruct {

 	char[] structName;

 	public char[] toString() {

 		return structName;

 	}
 	
 }

 ...

 class MyClass {

 	private static void function(void*) callBack;
 	private static void* callBackValue;
 	...
 	static this() {
 		MyStruct test = MyStruct();
 		test.structName = "Struct name";
 		callBack =&cb;
 		callBackValue =&test;
 	}
 	...
 	public void cb(void* value) {

 		MyStruct temp = *((cast(MyStruct*) value));
 		writefln(temp);

 	}

 }

Why the need for void* everywhere? Surely you could save the effort and store it as a MyStruct?

Because I call MyClass.cb by using an other class... for example the Button-Class. struct MyStruct { char[] structName; public char[] toString() { return structName; } } ... class MyClass { public static Button[] loadButtons() { Button[] buttons; for (int i=0; i < 10; i++) { MyStruct curStruct = MyStruct(); curStruct.structName = .toString(i); buttons ~= new Button(cb, curStruct); } return buttons; } public static void cb(void* value) { MyStruct temp = *((cast(MyStruct*) value)); writefln(temp); } } class Button { private static void function(void*) callBack; private static void* callBackValue; this(void function(void*) cB, void* cbValue) { callBack = cB; callBackValue = cbValue; } public void pressButton() { // This should call MyClass.cb callBack(callBackValue); } } For example... I click on a button on my OpenGL-gui, then I simply call the pressButton-method in my class Button which should call MyClass.cb with callBackValue which can be a value, class, struct or a similar datatype. To store different values/classes/structs... I cast all to a void-pointer. In this case I can use the Button-class in multiple situations.
Apr 11 2010
parent reply Robert Clipsham <robert octarineparrot.com> writes:
On 11/04/10 16:02, Nrgyzer wrote:
 Because I call MyClass.cb by using an other class... for example the
 Button-Class.

 For example... I click on a button on my OpenGL-gui, then I simply
 call the pressButton-method in my class Button which should call
 MyClass.cb with callBackValue which can be a value, class, struct or
 a similar datatype. To store different values/classes/structs... I
 cast all to a void-pointer. In this case I can use the Button-class
 in multiple situations.

By using templated classes you can remove the need for void*: ---- struct MyStruct { char[] structName; public char[] toString() { return structName; } } class MyClass { public static Button!(MyStruct)[] loadButtons() { Button!(MyStruct)[] buttons; for (int i=0; i< 10; i++) { MyStruct curStruct = MyStruct(); curStruct.structName = .toString(i); buttons ~= new Button!(MyStruct)(cb, curStruct); } return buttons; } public static void cb(MyStruct value) { writefln(value); } } class Button(T) { private static void function(T) callBack; private static T callBackValue; this(void function(T) cB, T cbValue) { callBack = cB; callBackValue = cbValue; } public void pressButton() { // This should call MyClass.cb callBack(callBackValue); } } ---- Of course this is more restrictive in some cases, such as if you wanted an array of buttons with different types for their callback and callbackValue, and it also adds template bloat if you have a lot of different types for buttons. There should be a way around this, I can't think of it off the top of my head though, perhaps someone else can.
Apr 11 2010
next sibling parent Nrgyzer <nrgyzer gmail.com> writes:
Robert Clipsham Wrote:

 On 11/04/10 16:02, Nrgyzer wrote:
 Because I call MyClass.cb by using an other class... for example the
 Button-Class.

 For example... I click on a button on my OpenGL-gui, then I simply
 call the pressButton-method in my class Button which should call
 MyClass.cb with callBackValue which can be a value, class, struct or
 a similar datatype. To store different values/classes/structs... I
 cast all to a void-pointer. In this case I can use the Button-class
 in multiple situations.

By using templated classes you can remove the need for void*: ---- struct MyStruct { char[] structName; public char[] toString() { return structName; } } class MyClass { public static Button!(MyStruct)[] loadButtons() { Button!(MyStruct)[] buttons; for (int i=0; i< 10; i++) { MyStruct curStruct = MyStruct(); curStruct.structName = .toString(i); buttons ~= new Button!(MyStruct)(cb, curStruct); } return buttons; } public static void cb(MyStruct value) { writefln(value); } } class Button(T) { private static void function(T) callBack; private static T callBackValue; this(void function(T) cB, T cbValue) { callBack = cB; callBackValue = cbValue; } public void pressButton() { // This should call MyClass.cb callBack(callBackValue); } } ---- Of course this is more restrictive in some cases, such as if you wanted an array of buttons with different types for their callback and callbackValue, and it also adds template bloat if you have a lot of different types for buttons. There should be a way around this, I can't think of it off the top of my head though, perhaps someone else can.

Yeah, that's a solution I didn't think about :). Thanks...
Apr 11 2010
prev sibling parent Nrgyzer <nrgyzer gmail.com> writes:
Robert Clipsham Wrote:

 On 11/04/10 16:02, Nrgyzer wrote:
 Because I call MyClass.cb by using an other class... for example the
 Button-Class.

 For example... I click on a button on my OpenGL-gui, then I simply
 call the pressButton-method in my class Button which should call
 MyClass.cb with callBackValue which can be a value, class, struct or
 a similar datatype. To store different values/classes/structs... I
 cast all to a void-pointer. In this case I can use the Button-class
 in multiple situations.

By using templated classes you can remove the need for void*: ---- struct MyStruct { char[] structName; public char[] toString() { return structName; } } class MyClass { public static Button!(MyStruct)[] loadButtons() { Button!(MyStruct)[] buttons; for (int i=0; i< 10; i++) { MyStruct curStruct = MyStruct(); curStruct.structName = .toString(i); buttons ~= new Button!(MyStruct)(cb, curStruct); } return buttons; } public static void cb(MyStruct value) { writefln(value); } } class Button(T) { private static void function(T) callBack; private static T callBackValue; this(void function(T) cB, T cbValue) { callBack = cB; callBackValue = cbValue; } public void pressButton() { // This should call MyClass.cb callBack(callBackValue); } } ---- Of course this is more restrictive in some cases, such as if you wanted an array of buttons with different types for their callback and callbackValue, and it also adds template bloat if you have a lot of different types for buttons. There should be a way around this, I can't think of it off the top of my head though, perhaps someone else can.

I tried a bit with templates and classes - without success. I always get the following error: "Error: template instance Button!(myStruct) forward references template declaration Button(T)" when I try to create a Button array like this one: private Button!(T)[]; That's exactly the same error message which was posted on http://www.digitalmars.com/d/archives/digitalmars/D/bugs/Issue_3834_New_forward_reference_in_templated_class_21207.html
Apr 11 2010
prev sibling parent Justin Spahr-Summers <Justin.SpahrSummers gmail.com> writes:
On Sun, 11 Apr 2010 10:41:29 -0400, Nrgyzer <nrgyzer gmail.com> wrote:
 ...
 
 class MyClass {
 
 	private static void function(void*) callBack;
 	private static void* callBackValue;
 	...
 	static this() {
 		MyStruct test = MyStruct();
 		test.structName = "Struct name";
 		callBack = &cb;
 		callBackValue = &test;
 	}

In this function, 'test' is allocated on the stack and therefore only exists for the duration of the function call. When the static constructor finishes, any pointers directed at 'test' are basically garbage and should never be used. There are three workarounds: 1. Store 'test' in a place where it won't get destructed until you're done using it. 2. Allocate 'test' on the heap by using a pointer and 'new'. 3. Change MyStruct into a class so objects are allocated on the heap by default. This is probably the best solution for situations like this, especially given your explanation of what you're trying to do.
Apr 11 2010