Sign in Join

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

Mailing lists / fpc-pascal / 2005-10

Records

11 messages · 6 people ·

Reply by email Subscribe to this list Your subscription

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

Carsten Bager

We are moving a lot of code from an old platform where it is allowed to compare 2 records like this.

Type
  A_typ=array[0..3] of integer;
Var
 A1,A2:A_typ;
Begin
  If A1=A2 then
End;

I know that I can typecast to an array of char to compare but is there an easier way.

---

I have never could understand when this is allowed
A1:=A2;
Why this is not allowed
If A1=A2 then

in most Pascal compilers.

Regards Carsten

Carsten Bager Bøvlingbjerg El-automatik Brørupvænget 10 7650 Bøvlingbjerg Tlf. +4597885222 Fax +4597885434 http://www.beas.dk
Adriaan van Os
to Carsten Bager
Carsten Bager wrote 24 lines
We are moving a lot of code from an old platform where it is allowed to compare 2 records like this. Type A_typ=array[0..3] of integer; Var A1,A2:A_typ; Begin If A1=A2 then End; I know that I can typecast to an array of char to compare but is there an easier way. --- I have never could understand when this is allowed A1:=A2; Why this is not allowed If A1=A2 then in most Pascal compilers.

Because you can't simply compare the memory ranges occupied by records A and B. They could have different pad bytes (and bits) but still be the same. Therefore, implementation is non-trivial. For the same reason, the above typecast is incorrect.

Regards,

Adriaan van Os

Florian Klaempfl
to Adriaan van Os
Adriaan van Os wrote 33 lines
Carsten Bager wrote: > We are moving a lot of code from an old platform where it is > allowed to compare 2 records like this. > > Type > A_typ=array[0..3] of integer; > Var > A1,A2:A_typ; > > Begin > If A1=A2 then > End; > > I know that I can typecast to an array of char to compare but > is there an easier way. > > --- > > I have never could understand when this is allowed > A1:=A2; > > Why this is not allowed > If A1=A2 then > > in most Pascal compilers. Because you can't simply compare the memory ranges occupied by records A and B. They could have different pad bytes (and bits) but still be the same. Therefore, implementation is non-trivial. For the same reason, the above typecast is incorrect.

We could implement such a comparisation based on rtti ...

Carsten Bager
to Florian Klaempfl
Show quoted text 34 lines
Adriaan van Os wrote: > Carsten Bager wrote: > >> We are moving a lot of code from an old platform where it is >> allowed to compare 2 records like this. >> >> Type >> A_typ=array[0..3] of integer; >> Var >> A1,A2:A_typ; >> >> Begin >> If A1=A2 then >> End; >> >> I know that I can typecast to an array of char to compare but >> is there an easier way. >> >> --- >> >> I have never could understand when this is allowed >> A1:=A2; >> >> Why this is not allowed >> If A1=A2 then >> >> in most Pascal compilers. > > > Because you can't simply compare the memory ranges occupied by records A > and B. They could have different pad bytes (and bits) but still be the > same. Therefore, implementation is non-trivial. For the same reason, the > above typecast is incorrect.

I have never used this without initializing records first (A1:=A2). I have used it on deferent platforms (on PC's with typecast). It has all ways don what I expected.
It could be a demand that records should be packed, but that triggers another problem on some (ARM) platforms.

> We could implement such a comparisation based on rtti ...

I assume that rtti means "Runtime Type Information", something a have never used, but if it can do the job I would be happy.

Regards Carsten

_______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Micha Nelissen
to Adriaan van Os: Because you can't simply compare the memory ranges occupied by records A and B. They…
Adriaan van Os wrote 12 lines
> I have never could understand when this is allowed > A1:=A2; > > Why this is not allowed > If A1=A2 then > > in most Pascal compilers. Because you can't simply compare the memory ranges occupied by records A and B. They could have different pad bytes (and bits) but still be the same.

Isn't the number of pad bytes a property of a type ? So when two vars are of the same type, they also have the same number of pad bytes ?

Or: the compiler could also do the equivalent of sizeof(a1)=sizeof(a2), if equal then can compare "easy" (same number of pad bytes), otherwise give appropriate error (size of type differs, or so).

Micha

Jonas Maebe
to Micha Nelissen
Micha Nelissen wrote 7 lines
> Because you can't simply compare the memory ranges occupied by > records A and B. They could have different pad bytes (and bits) > but still be the same. Isn't the number of pad bytes a property of a type ? So when two vars are of the same type, they also have the same number of pad bytes ?

Yes, but two different variables of the same type could have different values for those pad bytes. So you have to compare everything but the pad bytes.

Jonas

Micha Nelissen
to Jonas Maebe
Jonas Maebe wrote
Yes, but two different variables of the same type could have different values for those pad bytes. So you have to compare everything but the pad bytes.

Oh right! Something like a masked compare or so...probably not implementable in an efficient way indeed I guess.

Micha

Adriaan van Os
to Jonas Maebe: Yes, but two different variables of the same type could have different values for those…
Jonas Maebe wrote 12 lines
Micha Nelissen wrote: >> Because you can't simply compare the memory ranges occupied by >> records A and B. They could have different pad bytes (and bits) but >> still be the same. > > Isn't the number of pad bytes a property of a type ? So when two vars > are of the same type, they also have the same number of pad bytes ? Yes, but two different variables of the same type could have different values for those pad bytes. So you have to compare everything but the pad bytes.

Yes, consider

	type myRec = record b: boolean; l: longint end;

Dependent on the alignment (and packing) mode there can be 0, 1 or 3 pad bytes between the two fields.

By the way, in a similar thread about this subject for gpc (<http://www.gnu-pascal.de/crystal/gpc/en/thread12594.html>) a perl script was posted
(<http://www.gnu-pascal.de/crystal/gpc/en/mail12604.html>) that automatically creates comparison operators for record types. I haven't checked if it works with fpc.

Regards,

Adriaan van Os

Vinzent Hoefler
to Micha Nelissen: Oh right! Something like a masked compare or so...probably not implementable in an…
Micha Nelissen wrote 7 lines
Jonas Maebe wrote: > Yes, but two different variables of the same type could have > different values for those pad bytes. So you have to compare > everything but the pad bytes. Oh right! Something like a masked compare or so...probably not implementable in an efficient way indeed I guess.

Whatever you call efficient. A simple memory compare won't do, as others already pointed out, and everything else depends on the actual layout of the structure.

Let's take a look at a compiler which does such nasty things:

--8< -- snip --
with Ada.Text_IO;

procedure t is

   type Padded_Record is
      record
         A : Integer range 0 .. 3;
         B : Integer range 0 .. 30000;
      end record;
   for Padded_Record use
      record
         A at 0 range 3 ..  5; -- use bits [5:3] of byte 0
         B at 3 range 1 .. 15; -- use bits [15:1] of bytes 3 and 4
      end record;
   function Compare (Left, Right : Padded_Record) return Boolean is
   begin
      return Left = Right;
   end Compare;
   X, Y : Padded_Record;
begin
   X.A := 2;
   X.B := 20000;
   Y := X;
   Ada.Text_IO.Put_Line (Boolean'Image (Compare (X, Y)));
end t;
--8< -- snip --

The interesting compare function after compiled with gcc3.1.1's "gnatmake -f -S -O3 -fomit-frame-pointer t.adb" we get:

-- 8< -- snip --
t__compare.0:
pushl %esi
xorl %esi, %esi
pushl %ebx
pushl %ebx
movl %ecx, (%esp)
movl 20(%esp), %ebx
movl 16(%esp), %ecx
movb (%ebx), %al
movb (%ecx), %dl
andl $56, %eax
andl $56, %edx
cmpb %al, %dl
je .L49
.L42:
movl %esi, %eax
popl %edx
popl %ebx
popl %esi
ret
.p2align 4,,7
.L49:
movb 3(%ecx), %dl
xorl %eax, %eax
movb 4(%ecx), %cl
movb 4(%ebx), %al
shrb %dl
andl $255, %ecx
sall $7, %ecx
andl $255, %edx
sall $7, %eax
orl %edx, %ecx
movb 3(%ebx), %dl
shrb %dl
andl $255, %edx
orl %edx, %eax
cmpw %ax, %cx
jne .L42
movl $1, %esi
jmp .L42
-- 8< -- snip --

Of course, the type layout I forced here is really nasty, the resulting code looks quite a lot better to me when B start at bit 0 again.

Vinzent.

Micha Nelissen
to Vinzent Hoefler
Vinzent Hoefler wrote 7 lines
>Oh right! Something like a masked compare or so...probably not >implementable in an efficient way indeed I guess. Whatever you call efficient. A simple memory compare won't do, as others already pointed out, and everything else depends on the actual layout of the structure.

Your structure is very short, code length will explode for larger structures. It's inefficient compared to "REPE CMPSD" with proper context, this is only a few lines.

Show quoted text 10 lines
andl $56, %eax andl $56, %edx cmpb %al, %dl je .L49 .L42: movl %esi, %eax popl %edx popl %ebx popl %esi ret

What does this part do btw? Compare lengths?

Micha

Vinzent Hoefler
to Micha Nelissen
Micha Nelissen wrote 10 lines
Vinzent Hoefler wrote: >>Oh right! Something like a masked compare or so...probably not >>implementable in an efficient way indeed I guess. > > Whatever you call efficient. A simple memory compare won't do, as > others already pointed out, and everything else depends on the > actual layout of the structure. Your structure is very short, code length will explode for larger structures.

Yes, of course, especially when the structures do not contain large fields of contiguous data which can be compared with "repe cmpsd" or whatever equivalents other processors besides x86 might have.

But that would - of course - also be the case, if you write your own comparison function in the higher level language (without specialized typecasts).

It's inefficient compared to "REPE CMPSD" with proper context, this is only a few lines.

Precisely. But that's just the way it has to be, there's no way around it unless you assume that unused padding bits/bytes always have the same value (which could be a wrong assumption in quite a lot of cases - try reading such values from an external hardware device with unused connections left floating).

For these sort of things, it will be as inefficient as it can get either way, no matter if you let the compiler do the work or if you come up with your own comparison function.

Show quoted text 12 lines
> andl $56, %eax > andl $56, %edx > cmpb %al, %dl > je .L49 > .L42: > movl %esi, %eax > popl %edx > popl %ebx > popl %esi > ret What does this part do btw? Compare lengths?

No, it masks off the unused bits (Padded_Record.A is located in the middle of an octett like this XXX---XXX) and then does the comparison, I would suppose. It falls through directly to the exit code (restoring saved registers, and then returning the value) at .L42 if the comparison already fails. I really meant it, when I wrote, that the structure I told the compiler to build up is quite nasty. ;-)

Vinzent.