Thread overview
Wrong pointer calculation without casting on struct
Feb 06, 2015
tcak
Feb 06, 2015
tcak
Feb 06, 2015
Baz
Feb 06, 2015
Ali Çehreli
February 06, 2015
I am on 64-bit Linux.

I defined a struct that it 8 bytes in total.

align(1) struct MessageBase{
align(1):
	ushort qc;
	ushort wc;
	ushort id;
	ushort contentLength;
	void[0] content;
}


I defined a function in this struct that tries to set a pointer to "contentLength" field.

writeln( "Without: ", (&this + id.offsetof) );
writeln( "With   : ", (cast(size_t)&this + id.offsetof) );

Results:
Without: 7FFFF74F5030
With   : 140737342558228

0x7FFFF74F5030 => 140737342558256


As it is seen, there is 28 bytes of difference between them. What is this behaviour exactly?
February 06, 2015
On Friday, 6 February 2015 at 03:59:51 UTC, tcak wrote:
> I am on 64-bit Linux.
>
> I defined a struct that it 8 bytes in total.
>
> align(1) struct MessageBase{
> align(1):
> 	ushort qc;
> 	ushort wc;
> 	ushort id;
> 	ushort contentLength;
> 	void[0] content;
> }
>
>
> I defined a function in this struct that tries to set a pointer to "contentLength" field.
>
> writeln( "Without: ", (&this + id.offsetof) );
> writeln( "With   : ", (cast(size_t)&this + id.offsetof) );
>
> Results:
> Without: 7FFFF74F5030
> With   : 140737342558228
>
> 0x7FFFF74F5030 => 140737342558256
>
>
> As it is seen, there is 28 bytes of difference between them. What is this behaviour exactly?

By the way,

writeln("Base Normal: ", &this);
writeln("Base Cast  : ", cast(size_t)&this);

Result:
Base Normal: 7FFFF74F5010
Base Cast  : 140737342558224

0x7FFFF74F5010 => 140737342558224

These are same. So, the issue is about addition process.
February 06, 2015
On Friday, 6 February 2015 at 04:10:08 UTC, tcak wrote:
> On Friday, 6 February 2015 at 03:59:51 UTC, tcak wrote:
>> I am on 64-bit Linux.
>>
>> I defined a struct that it 8 bytes in total.
>>
>> align(1) struct MessageBase{
>> align(1):
>> 	ushort qc;
>> 	ushort wc;
>> 	ushort id;
>> 	ushort contentLength;
>> 	void[0] content;
>> }
>>
>>
>> I defined a function in this struct that tries to set a pointer to "contentLength" field.
>>
>> writeln( "Without: ", (&this + id.offsetof) );
>> writeln( "With   : ", (cast(size_t)&this + id.offsetof) );
>>
>> Results:
>> Without: 7FFFF74F5030
>> With   : 140737342558228
>>
>> 0x7FFFF74F5030 => 140737342558256
>>
>>
>> As it is seen, there is 28 bytes of difference between them. What is this behaviour exactly?
>
> By the way,
>
> writeln("Base Normal: ", &this);
> writeln("Base Cast  : ", cast(size_t)&this);
>
> Result:
> Base Normal: 7FFFF74F5010
> Base Cast  : 140737342558224
>
> 0x7FFFF74F5010 => 140737342558224
>
> These are same. So, the issue is about addition process.

I've tried this;

import std.stdio;

struct MessageBase{
align(1):
	ushort qc;
	ushort wc;
	ushort id;
	ushort contentLength;
	void[0] content;

    void a(){
        writefln("%.8X",(cast(void*)&this + id.offsetof));
        writefln("%.8X",(cast(size_t)&this + id.offsetof));
    }
}


void main()
{
    MessageBase mb;
    mb.a;
}

and got the same value for both. Your problem is:

typeof(&this).stringof is "MessageBase*" so with ptr arithmetic when you add 1 you actually shift by 1 * MessageBase.sizeof.

typeof(cast(void*)&this) is "void*" so with ptr arithmetic you shift by a certain number of bytes.
February 06, 2015
On 02/05/2015 07:59 PM, tcak wrote:

> writeln( "Without: ", (&this + id.offsetof) );

In pointer arithmetic, the increment value means "that many *objects* away", not "than many bytes away".

Since id.offsetof is 4, you are calculating 4 MessageBase objects away (4*8==32 bytes away).

> writeln( "With   : ", (cast(size_t)&this + id.offsetof) );

That is not pointer arithmetic, so the increment is just 4.

32 - 4 == 28.

Ali