Sign in Join

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

Mailing lists / lazarus / 2012-07

C Integer types

18 messages · 7 people · –

Reply by email Subscribe to this list Your subscription

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

Dave Coventry

I have the following C code which I'm trying to emulate in Pascal:

  seqence_crc = *((int64_t*)data);
  seqence_key = *((int64_t*)&data[8]);
  compr_crc   = *((int64_t*)&data[16]);
  compr_len   = *((int32_t*)&data[24]);

Currently, I'm doing it manually, but I'm not getting the results I'm expecting.

I'm pretty sure there is a way of doing this natively, but I can't seem to find it.

Regards,

Dave

Reply by email

Marco van de Voort
to Dave Coventry

In our previous episode, Dave Coventry said:

Show quoted text 8 lines
I have the following C code which I'm trying to emulate in Pascal: seqence_crc = *((int64_t*)data); seqence_key = *((int64_t*)&data[8]); compr_crc = *((int64_t*)&data[16]); compr_len = *((int32_t*)&data[24]); Currently, I'm doing it manually, but I'm not getting the results I'm expecting.

This assumes data is a pbyte or pchar (char * or byte *)

then & translates to @, and int64_t* to pint64 the first * changes to ^ at the end:

   seqence_crc:=pint64(data)^;
   seqence_key:=pint64(@data[8])^;
   compr_crc:=pint64(@data[16])^;
   compr_len:=pint64(@data[24])^;
I'm pretty sure there is a way of doing this natively, but I can't seem to find it.

It's 1:1 translatable. Note the absence of @ and & in the first line though, that is on purpose. (in both fragments)

Reply by email

Dave Coventry
to Marco van de Voort

Thanks Marco,

I'll try that.

Marco van de Voort wrote 31 lines
In our previous episode, Dave Coventry said: > I have the following C code which I'm trying to emulate in Pascal: > > seqence_crc = *((int64_t*)data); > seqence_key = *((int64_t*)&data[8]); > compr_crc = *((int64_t*)&data[16]); > compr_len = *((int32_t*)&data[24]); > > Currently, I'm doing it manually, but I'm not getting the results I'm expecting. This assumes data is a pbyte or pchar (char * or byte *) then & translates to @, and int64_t* to pint64 the first * changes to ^ at the end: seqence_crc:=pint64(data)^; seqence_key:=pint64(@data[8])^; compr_crc:=pint64(@data[16])^; compr_len:=pint64(@data[24])^; > I'm pretty sure there is a way of doing this natively, but I can't > seem to find it. It's 1:1 translatable. Note the absence of @ and & in the first line though, that is on purpose. (in both fragments) -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

Reply by email

Dave Coventry
to Hans-Peter Diettrich: or seqence_crc:=pint64(@data[0])^; For the curious and nonbelievers: Array syntax can be…

Can I assume that you hadn't noticed that compr_len = *((int32_t*)&data[24]); was a 32 bit integer?

Is there such a thing as pint32? (Google suggests that a pint is 32 half-ounces)

compr_len:=pint64(@data[24])^;

?

Hans-Peter Diettrich wrote 38 lines
Marco van de Voort schrieb: > This assumes data is a pbyte or pchar (char * or byte *) > > then & translates to @, and int64_t* to pint64 the first * changes to ^ at > the end: > > seqence_crc:=pint64(data)^; or seqence_crc:=pint64(@data[0])^; > seqence_key:=pint64(@data[8])^; > compr_crc:=pint64(@data[16])^; > compr_len:=pint64(@data[24])^; > >> I'm pretty sure there is a way of doing this natively, but I can't >> seem to find it. > > > It's 1:1 translatable. Note the absence of @ and & in the first line > though, > that is on purpose. (in both fragments) For the curious and nonbelievers: Array syntax can be used in the first line, too, see above. DoDi -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

Reply by email

Hans-Peter Diettrich
to Marco van de Voort: In our previous episode, Dave Coventry said: This assumes data is a pbyte or pchar (char…
Show quoted text 6 lines
This assumes data is a pbyte or pchar (char * or byte *) then & translates to @, and int64_t* to pint64 the first * changes to ^ at the end: seqence_crc:=pint64(data)^;
or
      seqence_crc:=pint64(@data[0])^;
Show quoted text 9 lines
seqence_key:=pint64(@data[8])^; compr_crc:=pint64(@data[16])^; compr_len:=pint64(@data[24])^; > I'm pretty sure there is a way of doing this natively, but I can't > seem to find it. It's 1:1 translatable. Note the absence of @ and & in the first line though, that is on purpose. (in both fragments)

For the curious and nonbelievers:
Array syntax can be used in the first line, too, see above.

DoDi

Reply by email

Hans-Peter Diettrich
to Dave Coventry: Can I assume that you hadn't noticed that compr_len = *((int32_t*)&data[24]); was a 32…
Can I assume that you hadn't noticed that compr_len = *((int32_t*)&data[24]); was a 32 bit integer?

Right, such errors suggest the use of translation tools instead of manual translation.

Is there such a thing as pint32? (Google suggests that a pint is 32 half-ounces)

;-)

compr_len:=pint64(@data[24])^;

int32_t* is definitely a pointer to an 32 bit signed integer. You can create this type yourself, if it doesn't exist.

DoDi

Reply by email

Bernd
to Marco van de Voort: In our previous episode, Dave Coventry said: This assumes data is a pbyte or pchar (char…

2012/7/7 Marco van de Voort :

seqence_crc:=pint64(data)^; seqence_key:=pint64(@data[8])^; compr_crc:=pint64(@data[16])^; compr_len:=pint64(@data[24])^;

How about defining something more pascalish first, a record type for example:

{$modeswitch autoderef}
type
  PDataHeader = ^TDataHeader;
  TDataHeader = record
    sequence_crc: QWord;
    sequence_key: QWord;
    compr_crc: QWord;
    compr_len: DWord;
  end;
var
  Data: PDataHeader;
  SeqCrc: QWord;
  SeqKey: QWord;
  ...
begin
  Data := WhereverThisComesFrom();
  SeqCrc := Data.sequence_crc;
  SeqKey := Data.sequence_key;
  ...

Reply by email

Hans-Peter Diettrich
to Bernd
Show quoted text 19 lines
2012/7/7 Marco van de Voort : > seqence_crc:=pint64(data)^; > seqence_key:=pint64(@data[8])^; > compr_crc:=pint64(@data[16])^; > compr_len:=pint64(@data[24])^; How about defining something more pascalish first, a record type for example: {$modeswitch autoderef} type PDataHeader = ^TDataHeader; TDataHeader = record sequence_crc: QWord; sequence_key: QWord; compr_crc: QWord; compr_len: DWord; end;

IMO all these members should be pointers, of size 64 bit according to the index increment (8 bytes?). Typecasts will be needed for 32 bit pointers, as demonstrated in above code.

DoDi

Reply by email

Bernd Kreuss
to Hans-Peter Diettrich
Hans-Peter Diettrich wrote
IMO all these members should be pointers, of size 64 bit according to the index increment (8 bytes?).

You are right, I didn't look carefully enough. Too much ad-hoc pointer arithmetics and dereferencing around too many corners within the same expression.

Thats exactly the reason why I believe that defining types that describe the data (especially the more complex and not so obvious structures) *before* actually starting to write code that operates on it is better than the other way around. IMHO this particular piece of C code is ugly in more than only one regard. Even in C this could have been written cleaner and easier to read.

Bernd

Reply by email

waldo kitty
to Bernd: 2012/7/7 Marco van de Voort : How about defining something more pascalish first, a record…
Bernd wrote 6 lines
2012/7/7 Marco van de Voort: > seqence_crc:=pint64(data)^; > seqence_key:=pint64(@data[8])^; > compr_crc:=pint64(@data[16])^; > compr_len:=pint64(@data[24])^;

the above doesn't seem correct... i've been watching and waiting for someone to catch it... i think one did but no one has followed up that...

here is the original from Dave Coventry

Show quoted text 6 lines
I have the following C code which I'm trying to emulate in Pascal: seqence_crc = *((int64_t*)data); seqence_key = *((int64_t*)&data[8]); compr_crc = *((int64_t*)&data[16]); compr_len = *((int32_t*)&data[24]);

i see three int64's and one int32... it looks like marco's pint64 on the last line is incorrect and that maybe it should be pint32... this was actually asked about and it was noted that google was returning results for 32 pints of beer or such...

How about defining something more pascalish first, a record type for example:

i would agree with this since it is more readable ;)

Show quoted text 10 lines
{$modeswitch autoderef} type PDataHeader = ^TDataHeader; TDataHeader = record sequence_crc: QWord; sequence_key: QWord; compr_crc: QWord; compr_len: DWord; end;

and it looks like here you did see and allow for 64bit on the first three and 32bit on the last one...

Show quoted text 6 lines
var Data: PDataHeader; SeqCrc: QWord; SeqKey: QWord; ...

and as long as CompLen is a DWORD, this should work... i think? or am i missing something on the higher up pint64 stuff??

Reply by email

Bernd K.
to Hans-Peter Diettrich: IMO all these members should be pointers, of size 64 bit according to the index increment…
Hans-Peter Diettrich wrote 5 lines
Bernd schrieb: > 2012/7/7 Marco van de Voort : IMO all these members should be pointers, of size 64 bit according to the index increment (8 bytes?). Typecasts will be needed for 32 bit pointers, as demonstrated in above code.

Wait a monment, I have again think I was right and my other email admitting that I was wrong was wrong.

seqence_crc = *((int64_t*)data);
seqence_key = *((int64_t*)&data[8]);

from the inside out:
data is a pointer, say it points to a buffer
(int64_t*)data still points to that buffer
*((int64_t*)data) are bytes 0..7 of that buffer as int64.

now the second line

seqence_key = *((int64_t*)&data[8]);

data[8] is the same as *(data+8)
data[8] represents the 8th byte of that buffer (already dereferenced!) &data[8] is the address of that byte
&data[8] would be the same as (data+8)
((int64_t*)&data[8]) is still the same pointer
*((int64_t*)&data[8]) are bytes 8..17 of that buffer as int64

this should be equivalent:
seqence_crc = *((int64_t*)&data[0]);
seqence_key = *((int64_t*)&data[8]);
compr_crc   = *((int64_t*)&data[16]);
compr_len   = *((int32_t*)&data[24]);
and this also:
seqence_crc = *((int64_t*)data);
seqence_key = *((int64_t*)(data+8));
compr_crc   = *((int64_t*)(data+16));
compr_len   = *((int32_t*)(data+24));

Its really just a simple record with 4 numbers in it.

Bernd

Reply by email

Hans-Peter Diettrich
to Bernd Kreuss: You are right, I didn't look carefully enough. Too much ad-hoc pointer arithmetics and…
Show quoted text 13 lines
On 08.07.2012 17:18, Hans-Peter Diettrich wrote: > IMO all these members should be pointers, of size 64 bit according to > the index increment (8 bytes?). You are right, I didn't look carefully enough. Too much ad-hoc pointer arithmetics and dereferencing around too many corners within the same expression. Thats exactly the reason why I believe that defining types that describe the data (especially the more complex and not so obvious structures) *before* actually starting to write code that operates on it is better than the other way around.

Often it is not desired, or even not possible, to describe a commonly used data structure with properly typed members (cyclic unit references!). That's when even in Pascal untyped pointers or handles have to be passed around, which have a specific meaning only in specific parts of the code.

DoDi

Reply by email

Hans-Peter Diettrich
to Bernd K.: Wait a monment, I have again think I was right and my other email admitting that I was…
Show quoted text 15 lines
On 08.07.2012 17:18, Hans-Peter Diettrich wrote: > Bernd schrieb: >> 2012/7/7 Marco van de Voort : > IMO all these members should be pointers, of size 64 bit according to > the index increment (8 bytes?). Typecasts will be needed for 32 bit > pointers, as demonstrated in above code. Wait a monment, I have again think I was right and my other email admitting that I was wrong was wrong. seqence_crc = *((int64_t*)data); seqence_key = *((int64_t*)&data[8]); from the inside out: data is a pointer, say it points to a buffer

It's a variable, which can be an array.

(int64_t*)data still points to that buffer *((int64_t*)data) are bytes 0..7 of that buffer as int64.

No, as "int64_t*", what's a "^int64" in Pascal.

Show quoted text 6 lines
now the second line seqence_key = *((int64_t*)&data[8]); data[8] is the same as *(data+8) data[8] represents the 8th byte of that buffer (already dereferenced!)

It represents the 8th *element*, which here (most probably) is a byte. It could be something else, depending on the declaration of "data".

&data[8] is the address of that byte

This address is untyped in C - that's the trick and purpose of the entire construct. In OPL you can have both typed or untyped @ operators, depending on compiler options, but here a typecast into the real data type is required in either case.

&data[8] would be the same as (data+8) ((int64_t*)&data[8]) is still the same pointer

It's a pointer *starting* at that address.

*((int64_t*)&data[8]) are bytes 8..17 of that buffer as int64

The size of the pointer depends on the target memory model (16/32/64 bit). There is room for an 64 bit pointer in bytes 8..15, but how many bytes really are used depends on the sizeof(pointer).

Show quoted text 13 lines
this should be equivalent: seqence_crc = *((int64_t*)&data[0]); seqence_key = *((int64_t*)&data[8]); compr_crc = *((int64_t*)&data[16]); compr_len = *((int32_t*)&data[24]); and this also: seqence_crc = *((int64_t*)data); seqence_key = *((int64_t*)(data+8)); compr_crc = *((int64_t*)(data+16)); compr_len = *((int32_t*)(data+24)); Its really just a simple record with 4 numbers in it.

With 4 pointers in it, aligned to 8 byte boundaries.

DoDi

Reply by email

Hans-Peter Diettrich
to waldo kitty: the above doesn't seem correct... i've been watching and waiting for someone to catch…
Show quoted text 18 lines
> How about defining something more pascalish first, a record type for > example: i would agree with this since it is more readable ;) > {$modeswitch autoderef} > > type > PDataHeader = ^TDataHeader; > TDataHeader = record > sequence_crc: QWord; > sequence_key: QWord; > compr_crc: QWord; > compr_len: DWord; > end; and it looks like here you did see and allow for 64bit on the first three and 32bit on the last one...

When you declare the record properly:

   TDataHeader = record
     sequence_crc_Ptr,
     sequence_key_Ptr,
     compr_crc_Ptr: PInt64;
     compr_len_Ptr: PLongInt;
   end;

then its size depends on the size of an pointer. In 32 bit code the record size will be 16 bytes, in 64 bit code 32 bytes. But since the incoming data array has a fixed alignment, more wizardry is required to match precisely that layout in OPL.

DoDi

Reply by email

Bernd
to Hans-Peter Diettrich: It's a variable, which can be an array. No, as "int64_t*", what's a "^int64" in Pascal.…

Your explanations about pointers are 100% correct but it is not clear why you are interleaving them with my other explanations which makes it look as if you were trying to correct my comments but since there is nothing wrong with my comments, they are not conflicting, it is impossible to correct any mistakes. This will only confuse the reader.

2012/7/9 Hans-Peter Diettrich :

> Its really just a simple record with 4 numbers in it. With 4 pointers in it, aligned to 8 byte boundaries.

No, it contains the numbers directly. There are no pointers in the data. This other translation:

type
  PInt32 = ^Int32;
var
  data: Pointer;
  seqence_crc: Int64;
  seqence_key: Int64;
  compr_crc: Int64;
  compr_len: Int32;
begin
  seqence_crc:=PInt64(data)^;
  seqence_key:=PInt64(@data[8])^;
  compr_crc:=PInt64(@data[16])^;
  compr_len:=PInt32(@data[24])^;

based on the one from Marco in the second mail (I only changed the type of compr_len) which is also correct also clearly shows (clearly because its written in a readable language) that its just simply reading the values directly from the buffer whose address (the pointer to its first byte) is given in the variable data.

My initial translation with the record was 100% correct. Here it is again, this time using the IntXX type names for better comparison:

type
  PDataHeader = ^TDataHeader;
  TDataHeader = record
    sequence_crc: Int64;
    sequence_key: Int64;
    compr_crc: Int64;
    compr_len: Int32;
  end;
var
  data: PDataHeader;

The variable data would then be of type PDataHeader (I assume it is a header of something, so data would point to the first byte of that "something") and accessing the sequence_crc would go like this:

data^.sequence_crc

or if you enable autoderef it becomes even nicer:

data.sequence_crc

Bernd

Reply by email

Bernd
to Hans-Peter Diettrich: Often it is not desired, or even not possible, to describe a commonly used data structure…

2012/7/9 Hans-Peter Diettrich :

Often it is not desired, or even not possible, to describe a commonly used data structure with properly typed members (cyclic unit references!). That's when even in Pascal untyped pointers or handles have to be passed around, which have a specific meaning only in specific parts of the code.

I was criticizing the usage of obfuscating convoluted pointer arithmetics with hardcoded offsets to emulate something as simple as a record with 4 integers in it.

Even if you can't use the the original definition of that one record (why not?) you can still define the needed parts of that record a second time in a private type section (type is where knowledge about structure of data belongs) instead of hardcoding obscure byte offsets between begin/end where it clearly does *not* belong.

Bernd

Reply by email