Sign in to follow this  
Jiia

Strange Casting

Recommended Posts

Jiia    592
Very simple question.
class SomeClass, no deriving
{
public:
.. slew of functions ..
private:
  CHAR *Data;
};

// Is this safe?
SomeClass *object = new SomeClass;
.. some code that ends up with a string in the data pointer ..
sprintf( String, "String = %s", object );


Is it a given that the class and pointer exist in the same memory location? It's purely educational. I don't want to do this. Thanks

Share this post


Link to post
Share on other sites
doynax    850
Quote:
Original post by Jiia
Is it a given that the class and pointer exist in the same memory location?
In practice it depends on if the class has any virtual functions (i.e. a vtable).
Otherwise, even though the variable is guaranteed at offset zero within the structure I still suspect that the compiler is technically allowed to add additional padding. It's unlikely to be a problem for anything as large as a pointer but GCC has done something similar (padding a 16-bit structure to 32-bits on the ARM platform) to my code anyway..

You should also be aware that non-POD types are not guaranteed to be sent properly into a varadic function. So don't expect to use a class destructor to release the string.

edit: I just reread the code and it looks like you're sending the object by reference. You'll have to pass the object by value instead, otherwise the function will receive a pointer to a pointer.

Share this post


Link to post
Share on other sites
Jiia    592
Quote:
Original post by doynax
edit: I just reread the code and it looks like you're sending the object by reference. You'll have to pass the object by value instead, otherwise the function will receive a pointer to a pointer.

Are you sure? Normally, one would send object->Data to that sprintf call. But if object exists at memory location 0x079383, then doesn't object->Data exist there as well? If so, sending object should be the same as sending object->Data.

I think. It's a bit confusing :)

Thanks for the reply.

edit: Nope, I'm messing up. You're correct. Here's a better example:

VOID SortStrings(const CHAR **array, INT count);
SomeClass *strings = new SomeClass[16];
SortStrings( (CHAR**) strings, 16 );

I guess I'm pushing it even farther now, asking that the size of the structure be the same as it's data. Is this also always true with simple structures and classes (no virtuals or inheritance)? I guess this could be important when saving and reading chunks of data from file.

Share this post


Link to post
Share on other sites
doynax    850
Quote:
Original post by Jiia
I guess I'm pushing it even farther now, asking that the size of the structure be the same as it's data. Is this also always true with simple structures and classes (no virtuals or inheritance)? I guess this could be important when saving and reading chunks of data from file.
Farther? Your old code had that requirement too, to be fully compliant anyway.
And no, as I said earlier, there are no such guarantees.
Inheritance in itself is not a problem BTW, except virtual inheritance of course, it's only the vtable that'll mess up the structure.

Consider sending another string to printf in your old example, or a calling convention which pushes parameters on the stack in reverse order (pascal) or even one which requires the caller to cleanup the stack (stdcall).
Though to be fair neither of these calling conventions could normally be used on a variadic function on the x86 platform..

Share this post


Link to post
Share on other sites
Jiia    592
But are all of these differences compiler specific? There are no runtime reasons for a different outcome, right?

Take the saving to file issue I mentioned. What if I were to save and load classes in their entirety?
VOID Object::Save(FileClass &file)
{
file.Save( &StateData, sizeof(StateClass) );
file.Save( &AIData, sizeof(AIClass) );
file.Save( &WeaponData, sizeof(WeaponClass) );
}
VOID Object::Load(FileClass &file)
{
file.Load( &StateData, sizeof(StateClass) );
file.Load( &AIData, sizeof(AIClass) );
file.Load( &WeaponData, sizeof(WeaponClass) );
}


Would saving the data on one computer ever not work while loading on another? Would Save and Load type functions need to be written for every class to save every member? In some situations, this is needed anyway, such as the string pointer in my previous example. But are there any issues related to class sizes and data offsets?

Thanks again for your time.

Share this post


Link to post
Share on other sites
doynax    850
Quote:
Original post by Jiia
But are all of these differences compiler specific? There are no runtime reasons for a different outcome, right?
No, not really..

Quote:
Original post by Jiia
Would saving the data on one computer ever not work while loading on another? Would Save and Load type functions need to be written for every class to save every member? In some situations, this is needed anyway, such as the string pointer in my previous example. But are there any issues related to class sizes and data offsets?
No, that should work for the same build of the same program as long as you stick with the basic types (except pointers of course).
However simply changing your optimization settings in the compiler may be enough to break the binary compability.

Most compilers offer a special structure packing extension which can help with portability across different compilers/platforms. And defining a set of integer types with precise sizes (like the ones in C99's stdint.h) can help too.
But look out for unaligned accesses, different byteorders and different bitfield bitorders, etc..

Share this post


Link to post
Share on other sites
ToohrVyk    1595
C++ can guarantee at best that &(object->Data) == object, therefore, on the second line, your call is equivalent to:

sprintf( String, "String = %s", &(object->Data) );

Note that this is different from what you really wanted to do, which is:

sprintf( String, "String = %s", object->Data );

Data being private, the only way to get around this is to do:

sprintf( String, "String = %s", *(char**)object );

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this