Question

In pascal and delphi, arrays have their lengths stored at some offset in memory from the array's pointer. I found that the following code works for me and it gets the length of an array:

type PInt = ^Integer; //pointer to integer.

Function Length(Arr: PInt): Integer;
var
  Ptr: PInt;
Begin
  Ptr := Arr - sizeof(Integer);
  Result := Ptr^ + 1;
End;

Function High(Arr: PInt): Integer;  //equivalent to length - 1.
Begin
  Result := (Arr - sizeof(Integer))^;
End;

I translated the above code into C++ and it thus becomes:

int Length(int* Arr)
{
  int* Ptr = (Arr - sizeof(int));
  return *reinterpret_cast<char*>(Ptr) + 1;
}

int High(int* Arr)
{
    return *(Arr - sizeof(int));
}

Now assuming the above are equivalent to the Pascal/Delphi versions, how can I write a struct to represent a Pascal Array?

In other words, how can I write a struct such that the following is true:

Length(SomeStructPointer) = SomeStructPointer->size

I tried the following:

typedef struct
{
    unsigned size;
    int* IntArray;
} PSArray;

int main()
{
    PSArray ps;
    ps.IntArray = new int[100];
    ps.size = 100;

    std::cout<<Length((int*) &ps); //should print 100 or the size member but it doesn't.

    delete[] ps.IntArray;
}
Was it helpful?

Solution 2

Why? I can see no good reason to do this. Use idiomatic Pascal in Pascal, use idiomatic C++ in C++. Using sizeof like that also ignores padding, and so your results may vary from platform to platform.

If you want a size, store it in the struct. If you want a non-member length function, just write one that works with the way you wrote the struct. Personally, I suggest using std::array if the size won't change and std::vector if it will. If you absolutely need a non-member length function, try this:

template<typename T>
auto length(const T& t) -> decltype(t.size()) {
    return t.size();
}

That will work with both std::array and std::vector.

PS: If you're doing this for "performance reasons", please profile your code and prove that there is a bottleneck before doing something that will become a maintenance hazard.

OTHER TIPS

In Pascal and Delphi, arrays have their lengths stored at some offset in memory from the array's pointer.

This is not so. The entire premise of your question is wrong. The Delphi functions you present do not work in general. They might work for dynamic arrays. But it is certainly not the case that you can pass an pointer to an array and be sure that the length is stored before it.

And in fact the Delphi code in the question does not even work for dynamic arrays. Your pointer arithmetic is all wrong. You read a value 16 bytes to the left rather than 4 bytes. And you fail to check for nil. So it's all a bit of a disaster really.

Moving on to your C++ code, you are reaping the result of this false premise. You've allocated an array. There's no reason to believe that the int to the left of the array holds the length. Your C++ code is also very broken. But there's little point attempting to fix it because it can never be fixed. The functions you define cannot be implemented. It is simply not the case that an array is stored adjacent to a variable containing the length.

What you are looking for in your C++ code is std::vector. That offers first class support for obtaining the length of the container. Do not re-invent the wheel.

If interop is your goal, then you need to use valid interop types. And Delphi managed dynamic arrays do not qualify. Use a pointer to an array, and a separately passed length.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top