Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2018-01

Translate C code

8 messages · 5 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Darius Blaszyk

Hi all,

Again I would like to ask some support on a piece C code that I need to translate to pascal. The code in question is:

#define MEMNEXT(x) ((MyStruct *)(((char *) x) - ((char *) & (((MyStruct *)0)->next))))

What exactly is going on here? Where does the result point to? It seems like it starts with the pointer x and subtracts the size of the offset of the beginning of MyStruct up to the "next" variable. At least that's what I think is happening.

Does anyone has an idea how to translate this into working pascal code?

TIA!

Rgds, Darius

Reply by email

Karoly Balogh (Charlie/SGR
to Darius Blaszyk

Hi,

Darius Blaszyk wrote 9 lines
Again I would like to ask some support on a piece C code that I need to translate to pascal. The code in question is: #define MEMNEXT(x) ((MyStruct *)(((char *) x) - ((char *) & (((MyStruct *)0)->next)))) What exactly is going on here? Where does the result point to? It seems like it starts with the pointer x and subtracts the size of the offset of the beginning of MyStruct up to the "next" variable. At least that's what I think is happening.

Yes, it looks like it. It simply substracts the offset of the "next" field from the value of X; This is a better solution than hardwiring the offset of next, which could change depending on the target platform's structure padding, or other reasons (and sometimes could be hard to calculate by hand anyway).

Does anyone has an idea how to translate this into working pascal code?

Well, not sure why one needs to do this abomination, without knowing the data structure it operates on, but nevertheless, you can do the same in Free Pascal, but you better turn the macro into a function:

type
  PMyStruct = ^TMyStruct;
  TMyStruct = record
    some, fields: integer;
    next: PMyStruct;
  end;
function MEMNEXT(x: Pointer): PMyStruct;
begin
  MEMNEXT:=PMyStruct(PByte(x)-PByte(@(PMyStruct(nil)^.next)));
end;

If this function is used often, you can mark it as inline; So the compiler can inline it, whenever necessary. If you want to avoid pointermath for whatever reason, the same works if you cast the pointers to PtrUInt instead of a PByte.

If the input value of X is other than a pointer, you can either overloaded methods, or define a var parameter without type, for example.

Charlie

Reply by email

Ryan Joseph
to Karoly Balogh (Charlie/SGR: Yes, it looks like it. It simply substracts the offset of the "next" field from the value…
Show quoted text 13 lines
On Jan 6, 2018, at 1:49 PM, Karoly Balogh (Charlie/SGR) wrote: type PMyStruct = ^TMyStruct; TMyStruct = record some, fields: integer; next: PMyStruct; end; function MEMNEXT(x: Pointer): PMyStruct; begin MEMNEXT:=PMyStruct(PByte(x)-PByte(@(PMyStruct(nil)^.next))); end;

I’m curious about how this is intended to be used. What would the value of x be? This looks like a confusing way to write sizeof(TMyStruct) - Sizeof(pointer) but I’m confused myself.

Also why does @(PMyStruct(nil)^.next not crash? Dereferencing and taking the addressing of a nil pointer sounds like a bad idea.

Regards,
Ryan Joseph

Reply by email

Karoly Balogh (Charlie/SGR
to Ryan Joseph

Hi,

Ryan Joseph wrote
Also why does @(PMyStruct(nil)^.next not crash? Dereferencing and taking the addressing of a nil pointer sounds like a bad idea.

Because it doesn't do the actual dereferencing, because next's *VALUE* is never used, only it's address (due to the @ operator). Which is basically a fixed address of zero (nil) + a constant added together.

So it doesn't crash, because it never loads from this "invalid" address it calculates.

Charlie

Reply by email

Ryan Joseph
to Karoly Balogh (Charlie/SGR: Because it doesn't do the actual dereferencing, because next's *VALUE* is never used,…
On Jan 6, 2018, at 5:25 PM, Karoly Balogh (Charlie/SGR) wrote: So it doesn't crash, because it never loads from this "invalid" address it calculates.

Are we talking about the address on the stack at compile time? If no memory was ever allocated (which I thought nil suggested) then I don’t see where it’s getting an address of anything.

For anyone interested can you recode that function to more Pascal? It feels like we’re going needlessly low level when another method would make more sense.

Regards,
Ryan Joseph

Reply by email

Sven Barth
to Ryan Joseph
"Ryan Joseph" wrote 5 lines
On Jan 6, 2018, at 5:25 PM, Karoly Balogh (Charlie/SGR) < wrote: So it doesn't crash, because it never loads from this "invalid" address it calculates.

Are we talking about the address on the stack at compile time? If no memory was ever allocated (which I thought nil suggested) then I don’t see where it’s getting an address of anything.

In this case Nil does in fact have the address 0. Thus the address of a field in a record with address 0 is its offset in the record.

Regards,
Sven

Reply by email