Массивы Pascal и Delphi в массивы C / C ++

В паскале и delphi длины массивов хранятся с некоторым смещением в памяти от указателя массива. Я обнаружил, что следующий код работает для меня, и он получает длину массива:

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;

Я перевел приведенный выше код на C ++, и он стал:

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

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

Теперь, предполагая, что вышеизложенное эквивалентно версиям Pascal / Delphi, как я могу написать структуру для представления массива Pascal?

Другими словами, как я могу написать такую ​​структуру, чтобы верно следующее:

Length(SomeStructPointer) = SomeStructPointer->size

Я попробовал следующее:

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;
}

-1

Решение

Зачем? Я не вижу веских причин для этого. Используйте идиоматический Pascal в Pascal, используйте идиоматический C ++ в C ++. Подобное использование sizeof также игнорирует заполнение, поэтому ваши результаты могут отличаться в зависимости от платформы.

Если вы хотите размер, сохраните его в структуре. Если вы хотите использовать функцию, не связанную с длиной элемента, просто напишите такую, которая работает так же, как вы написали структуру. Лично я предлагаю использовать std::array если размер не изменится и std::vector если будет. Если вам абсолютно необходима функция длины, не связанной с членом, попробуйте это:

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

Это будет работать с обоими std::array а также std::vector,

PS: Если вы делаете это по «причинам производительности», пожалуйста, профилируйте свой код и докажите, что существует узкое место, прежде чем делать что-то, что станет опасным для обслуживания.

6

Другие решения

В Паскале и Дельфи длины массивов хранятся в
некоторое смещение в памяти от указателя массива.

Это не так. Вся предпосылка вашего вопроса неверна. Представленные вами Delphi-функции не работают вообще. Они могут работать для динамических массивов. Но это, конечно, не тот случай, когда вы можете передать указатель на массив и быть уверенным, что длина сохраняется перед ним.

На самом деле код Delphi, о котором идет речь, даже не работает для динамических массивов. Ваша арифметика с указателями неверна. Вы читаете значение 16 байтов слева, а не 4 байта. И вы не можете проверить на ноль. Так что все это на самом деле немного бедствия.

Переходя к вашему C ++ коду, вы пожинаете результат этого ложного предположения. Вы выделили массив. Нет оснований полагать, что int слева от массива содержит длину. Ваш код на C ++ также сильно поврежден. Но нет смысла пытаться исправить это, потому что это никогда не может быть исправлено. Определенные вами функции не могут быть реализованы. Это просто не тот случай, когда массив хранится рядом с переменной, содержащей длину.

Что вы ищете в своем C ++ коде, так это std :: vector. Это предлагает первоклассную поддержку для получения длины контейнера. Не изобретай велосипед заново.

Если ваша цель — взаимодействие, то вам нужно использовать допустимые типы взаимодействия. И Delphi управляемые динамические массивы не квалифицируются. Используйте указатель на массив и отдельно переданную длину.

7

По вопросам рекламы [email protected]