2

I am trying to "redefine" the UInt64 type for the Delphi 3 compiler. The reason for that is that I do not use system.pas nor sysinit.pas. So I only have native var types like Integer, Cardinal etc. How could I reproduce the UInt64?

Ben
  • 3,380
  • 2
  • 44
  • 98
  • 2
    Why don't you use system.pas? – Rob Dec 14 '13 at 09:57
  • @Rob because I don't it. I've never had problems without it until now. Delphi 7 doesn't support x64 so I don't even know why there is `UInt64`. – Ben Dec 14 '13 at 09:59
  • 1
    All good 32 bit compilers have support for 64 bit integers. D7 was lacking. What operations do you need to support. That is the key info that is missing. – David Heffernan Dec 14 '13 at 10:08
  • 1
    @DavidHeffernan I'm trying to port the latest `BTMemoryModule.pas` to make it work without `UInt64`. It uses `UInt64` so it supports x64 but I only need it for x86. – Ben Dec 14 '13 at 10:10
  • 1
    That's nice. What operations do you need. Question is meaningless without that info. – David Heffernan Dec 14 '13 at 10:13
  • @DavidHeffernan Like the pointer operations `IncP` and `DecP` and much much more that has `UInt64` operations. – Ben Dec 14 '13 at 10:16
  • @DavidHeffernan I appreciate your attempt to help but I think I just need to recode it with a little more effort so I can use it for x86. – Ben Dec 14 '13 at 10:22
  • 1
    You do need to enumerate all the operations that you need. You can use a real 32 bit compiler to lift code. For instance modern delphi or GCC or MSVC will all produce the 32 bit code to work with 64 bit operands. – David Heffernan Dec 14 '13 at 10:25
  • @DavidHeffernan But they still use `system.pas` and `sysinit.pas`. – Ben Dec 14 '13 at 10:26
  • 1
    Not GCC and MSVC. And modern delphi still writes code for 64 bit unsigned operations. Read that and learn. You do know asm right? – David Heffernan Dec 14 '13 at 10:28
  • @DavidHeffernan I will try to learn. And I don't know assembler yet. Thank you for the info. – Ben Dec 14 '13 at 10:34
  • 1
    If all you need is addition, that is quite easy. Easy enough to write a helper function to do that. – David Heffernan Dec 14 '13 at 10:51

2 Answers2

3

Delphi 7 doesn't have an unsigned 64-bit integer type. You can tell from its Windows.pas, where ULARGE_INTEGER is defined as a variant record holding either two unsigned 32-bit integers, or one signed 64-bit integer, which makes little sense, until you realise that that's simply the least bad alternative if you really need something that's binary compatible with unsigned 64-bit integer types from another system.

An unsigned 64-bit integer type requires compiler support, which your compiler lacks, so you cannot create it, sorry. Newer Delphi versions do have compiler support for it, so you might consider upgrading.

Delphi 3 is even worse, it doesn't have any 64-bit integer type, not even a signed one. Int64 was added in Delphi 4, and that might be sufficient to avoid the need for a working 64-bit unsigned integer type, but if you're stuck on Delphi 3, not even that will work.

As a side note, seemingly contrary to this answer, Delphi 7 does have a UInt64 type. However, this is highly misleading. It's a signed 64-bit integer type in this version, just like Int64.

  • Would there be a way to convert an address that points to `UInt64` to a regular `UInt` (32 bit)? – Ben Dec 14 '13 at 09:53
  • 2
    If a pointer points to a 64-bit value, you cannot convert it to a pointer that points to a 32-bit value without changing what it points to. But depending on your goals, you might be able to treat it as a pointer to `Int64` and use only operations that don't care whether you treat it as signed or unsigned. –  Dec 14 '13 at 10:14
  • I think that was wrong. I just wanted to know if it's possible to like convert a `UInt64` value which is lower than 4,294,967,297 and higher than -1 to a regular unsigned integer. And since I can't typecast/use `UInt64` I would have to work with pointers. – Ben Dec 14 '13 at 10:20
  • 1
    The conversion from `Int64` to `UInt32` produces the exact same value that the conversion from `UInt64` to `UInt32` would (assuming suitable compiler options -- no exceptions for out-of-range values), and the former should work even in Delphi 7. –  Dec 14 '13 at 10:26
  • Yeah but since I can't use `Int64` either, I'd have to find a way to convert it bit operations etc. Your answer has been accepted and I might consider upgrading. Thank you – Ben Dec 14 '13 at 10:28
  • 1
    Why can't you use `Int64`? You said you don't use System.pas, but `Int64` is one of the compiler built-in types, is it not? –  Dec 14 '13 at 10:31
  • That's the problem. `Int64` and `UInt64` are NOT declared in the compiler. – Ben Dec 14 '13 at 10:34
  • 2
    I know `UInt64` isn't, but `Int64` should be. I'll check when I can. –  Dec 14 '13 at 10:36
  • http://img4.imageshack.us/img4/9538/r0ns.png Please ignore all the other errors, etc. – Ben Dec 14 '13 at 10:39
  • 2
    @BenjaminWeiss "Version 10.0" isn't Delphi 7, it's Delphi 3. My Delphi 7 compiler says "Version 15.0". –  Dec 14 '13 at 10:44
  • 1
    @hvd 64 bit integer support on 32 bit compilers depends on helper functions to perform the operations. In Delphi they are implemented as intrinsics in the system unit. – David Heffernan Dec 14 '13 at 10:45
  • @hvd You are right! I totally forgot that I have to use an older compiler to bypass the 'Fatal: Cannot use reserved unit name 'System' error. Thank you for the reminder! – Ben Dec 14 '13 at 10:50
  • 1
    @DavidHeffernan Good point. Delphi 7 does have the `Int64` type, but no compiler support for 64-bit arithmetic, so the fact that it has the type doesn't help all that much. –  Dec 14 '13 at 10:50
  • 2
    @BenjaminWeiss Take a look at the Makefile in the Rtl directory, it contains the undocumented compiler option (`-y`) needed to compile System.pas with more recent compiler versions. (As a side note: it seems that Delphi 7 does actually define a `UInt64` built-in type... but it's not an unsigned 64-bit integer type.) –  Dec 14 '13 at 10:56
  • 1
    *An unsigned 64-bit integer type requires compiler support, which your compiler lacks, so you cannot create it, sorry.* That is simply not the case. – David Heffernan Dec 14 '13 at 12:34
  • 1
    @DavidHeffernan What you're doing is avoiding the need for an unsigned 64-bit integer type, by creating an 64-bit record type. It's a useful answer, but it doesn't contradict mine. Especially for Delphi versions that don't support operator overloading for record types. –  Dec 14 '13 at 12:38
  • 1
    The question asks, *How could I reproduce the UInt64?* All you do is repeat the observation from the question that the compiler does not support it. – David Heffernan Dec 14 '13 at 13:05
  • 1
    @DavidHeffernan The question makes an incorrect assumption, which is that Delphi 7 (when using RTL) supports an unsigned 64-bit integer type, and then asks how to do that without RTL. What I'm trying to point out in my answer is that Delphi 7 + RTL doesn't support that. That's not the same as what's in the question. (BTW, not sure why your answer got a downvote, that wasn't me. Like I said, it looks like a good follow-up to me.) –  Dec 14 '13 at 13:12
  • 1
    Once that incorrect assumption is dealt with, then the question remains of how to do 64 bit arithmetic without compiler support. Thanks for the upvote which I presume was you. – David Heffernan Dec 14 '13 at 13:29
  • 1
    Actually, that wasn't me either. I tend not to vote on answers to questions if one of those answers is mine. –  Dec 14 '13 at 13:31
  • Could you please edit your answer and replace `Delphi 7` with `Delphi 3`? It was my mistake cause I thought I've been using a Delphi 7 Compiler. I apologize. – Ben Dec 14 '13 at 21:01
  • 1
    @BenjaminWeiss Not a problem. Delphi 6 is just like Delphi 3 in not supporting 64-bit integer types, so I've simply kept it as Delphi 7, and Delphi before 7. –  Dec 14 '13 at 21:41
  • 1
    Your facts are off. Int64 was introduced in D4. – David Heffernan Dec 15 '13 at 03:21
  • 1
    @DavidHeffernan Oops, you're right, thanks. `Int64` support was more limited before Delphi 7, and for some purposes could not be used, but it *did* exist already. –  Dec 15 '13 at 10:36
  • 1
    Not really. It did not change between D4 and D7. – David Heffernan Dec 15 '13 at 10:39
  • 1
    @DavidHeffernan The lack of support for `Int64` in `Variant` types was a real problem that gradually improved and is supposed to completely work only in Delphi 7 and newer, is it not? –  Dec 15 '13 at 10:59
  • 1
    Variants? I wasn't talking about them. – David Heffernan Dec 15 '13 at 11:01
  • 1
    I was, I consider the conversion from `Int64` to other types as "`Int64` support". But I can understand if you'd rather label this specific conversion as "`Variant` support". –  Dec 15 '13 at 11:03
3

As I have explained in the comments, what really matters here is which operations you wish to support. The data type is simple enough. You represent it as two adjacent 32 bit integers. But the complexity lies in implementing the operations on that data type.

On a 32 bit machine, you cannot operate directly on 64 bit integers, so you need to build 64 bit operations using the functionality of the 32 bit CPU.

Here is an example of how to implement incrementing of an unsigned 64 bit integer by a signed 32 bit integer.

type
  UInt64 = record
    Lo: Cardinal;
    Hi: Cardinal;
  end;

procedure Increment(var op1: UInt64; op2: Integer);
// IN: eax = pointer to op1; edx = op2
asm
  mov ecx,eax
  mov eax,edx
  cdq
  add eax,[ecx]
  adc edx,[ecx+4]
  mov [ecx],eax
  mov [ecx+4],edx
end;

The tricky part of this function is the cdq instruction. That sign extends the signed double word in eax to a signed quad word in edx:eax.

Implementing other operations is broadly similar. Obviously addition is the simplest. Multiplication gets a little more difficult.


In the comments you state:

I am trying to port the latest BTMemoryModule.pas to make it work without UInt64. It uses UInt64 so it supports x64 but I only need it for x86.

Since you only need x86 support, because your compiler is 32 bit, then I don't think you actually need UInt64 operations. You replace those variables with Cardinal.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • +1 Thank you for your answer. I will try to replace it with Cardinal as soon as I get to it. – Ben Dec 14 '13 at 21:03
  • Btw. I have used your suggestion and it worked with `Cardinal`! :) – Ben Dec 16 '13 at 20:49
  • 1
    @BenjaminWeiss You could just as well have used an older version of BTMemoryModule, before it was ported to x64. I still cannot quite work out what hvd is trying to say in his answer. – David Heffernan Dec 16 '13 at 20:51