Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi SizeOf(NativeInt) vs C sizeof(int) on x86-64. Why the Size difference?

Preface

So after a long time of C only work I came back to Delphi and found out that there are some new things in Delphi. One being NativeInt.

To my surprise I discovered that Delphi and C handle their "native integer"1 types different for x86-64. Delphi NativeInt seems to behave like C void * and Delphi Pointer which is contrary to what I would expect from the names.

In Delphi NativeInt is 64 bit in size. Expressed in Code:

SizeOf(NativeInt) = SizeOf(Pointer) = SizeOf(Int64) = 8

C has only 64 bit pointers. int remains 32 bit. Expressed in Code2:

sizeof(int) == 4 != sizeof(void *) == 8

Even the Free Pascal Compiler3 agrees on the size of NativeInt.

Question

Why was 64 bit chosen for Delphi NativeInt and 32 bits for C int?

Of course both are valid according to the language documentation/specification. However, "the language allows for it" is not really a helpful answer.

I guess it has to do with speed of execution as this is the main selling point of C today. Wikipedia and other sources all say that x86-64 do have 64 bit operand registers. However, they also state that the default operand size is 32 bit. So maybe operations on 64 bit operands are slower compared to 32 bit operands? Or maybe the 64 bit registers can do 2 32 bit operations at the same time? Is that a reason?

Is there maybe another reason the creators of the compilers did choose these sizes?

Footnotes

  1. I am comparing Delphi NativeInt to C int because the name/specificaion suggests that they have similar purpose. I know there is also Delphi Integer which behaves like C int on x68 and x86-64 in Delphi.
  2. sizeof() returns the size as multiple of char in C. However, char is 1 byte on x86-64.
  3. It does so in Delphi mode and default mode for NativeInt. The other integer types in default mode are a whole other can of worms.
like image 816
RotatingPieces Avatar asked Sep 12 '13 18:09

RotatingPieces


1 Answers

NativeInt is simply an integer that is the same size as a pointer. Hence the fact that it changes size on different platforms. The documentation says exactly that:

The size of NativeInt is equivalent to the size of the pointer on the current platform.

The main use for NativeInt is to store things like operating system handles that behind the scenes are actually memory addresses. You are not expected to use it to perform arithmetic, store array lengths etc. If you attempt to do that then you make it much more difficult to share code between 32 and 64 bit versions of your program.

You can think of Delphi NativeInt as being directly equivalent to the .net type IntPtr. In C and C++ the OS handle types would commonly be declared as void* which is a pointer type rather than an integer type. However, you would perfectly well use a type like intptr_t if you so wished.

You use the term "native integer" to describe NativeInt, but in spite of the name it's very important to realise that NativeInt is not the native integer type of the language. That would be Integer. The native in NativeInt refers to the underlying hardware platform rather than the language.

The Delphi type Integer, the language native integer, matches up with the C type int, the corresponding language native type. And on Windows these types are 32 bits wide for both 32 and 64 bit systems.

When the Windows designers started working on 64 bit Windows, they had a keen memory of what had happened when int changed from 16 to 32 bits in the transition from 16 bit to 32 bit systems. That was no fun at all, although it was clearly the right decision. This time round, from 32 to 64, there was no compelling reason to make int a 64 bit type. Had the Windows designers done so, it would have made porting much harder work. And so they chose to leave int as a 32 bit type.

In terms of performance, the AMD64 architecture was designed to operate efficiently on 32 bit types. Since a 32 bit integer is half the size of a 64 bit integer, then memory usage is reduced by making int only 32 bits on a 64 bit system. And this will have a performance benefit.

A couple of comments:

  • You state that "C has only 64 bit pointers". That is not so. A 32 bit C compiler will generally use a flat 32 bit memory model with 32 bit pointers.
  • You also say, "in Delphi NativeInt is 64 bit in size". Again that is not so. It is either 32 or 64 bits wide depending on the target.
like image 93
David Heffernan Avatar answered Sep 28 '22 06:09

David Heffernan