32-битный и 64-битный разные типы длины динамического массива?

У меня есть набор тестов DUnitX, который отлично работает на Win32. Но когда я пытаюсь скомпилировать его для Win64, эта строка выдает ошибку компиляции:

Assert.AreEqual(4, Length(r.Values));

[Ошибка dcc64] ...: E2532 Не удалось вывести аргумент универсального типа из разных типов аргументов для метода AreEqual

r.Values ​​определяется как:

Type TIntegers = TArray<Integer>

Assert.AreEqual имеет разные перегруженные реализации, и dcc64 не может выбрать правильную... хорошо, но почему? И почему dcc32 может скомпилировать это без проблем?

Единственная подсказка, которая у меня есть, заключается в том, что если я наведу указатель мыши, Delphi скажет мне, что длина имеет тип System.Smallint. Не существует реализации Assert.AreEqual с параметрами Smallint... и, конечно же, если я приведу его к Integer, dcc64 скомпилирует его.

Но это меня сильно беспокоит. Если я загляну в модуль System.pas, я увижу, что DynArraySetLength принимает параметр NativeInt... 64-битное целое число (я бы ожидал беззнаковое, но не уверен в этом). Так почему же Length должна возвращать 16-битное целое число со знаком? Казалось бы, неприятности ждут своего часа, не так ли?

Что мне не хватает?


person Frazz    schedule 02.08.2017    source источник


Ответы (1)


В 64-битной версии TArray имеет длину типа Int64. Насколько я могу судить, для Int64 нет перегрузки AreEqual, поэтому он пытается использовать общую версию: AreEqual<>. Но похоже, что по параметрам он не может решить, какой из них.

Итак, в Win64 выполните:

 Assert.AreEqual<Int64>(4, Length(r.Values));

or

 Assert.AreEqual(4, Integer(Length(r.Values)));

Последнее конечно проще всего, так как должно работать в Win32 и Win64, но может не справиться с очень огромными массивами.


FWIW, Length не возвращает Smallint. Но для функций, которые различаются между платформами, особенно функций "магии компилятора", таких как Length, такая (неправильная) информация может появиться. Это проблема с IDE, а не с компилятором.

Обновлять:

Как сказал @RemyLebeau, может быть проще использовать вместо этого NativeInt. Это должно работать как для Win32, так и для Win64, поскольку NativeInt равно Int32 в Win32 и Int64 в Win64, а также то, что возвращает _DynArrayLength:

Assert.AreEqual<NativeInt>(4, Length(r.Values));
person Rudy Velthuis    schedule 02.08.2017
comment
Спасибо, Руди. Лучше иметь ошибку в IDE, чем в компиляторе :) Самое смешное, что на самом деле в моем тесте я сравнивал размер массива с Count реализации списка, и хотя первое зависит от платформы, второе Целое число на всех платформах. Теперь мне интересно, почему списки ограничены таким образом, поскольку они внутренне используют массив для хранения элементов. В любом случае, я выбрал общую форму, которую предпочитаю приведению типов, поскольку она делает утверждение более читабельным. Я не заметил такой перегрузки AreEqual. - person Frazz; 02.08.2017
comment
Это не совсем перегрузка. AreEqual и AreEqual<> — это разные имена, которые просто похожи на нас, людей. - person Rudy Velthuis; 02.08.2017
comment
Спасибо за исправление. Я просто хотел бы добавить, что универсальная версия AreEqual‹Int64› также компилируется и работает как в Win32, так и в Win64 (10.1 Berlin, но и дженерики, и Int64 были там некоторое время). - person Frazz; 02.08.2017
comment
Вместо этого я бы использовал Assert.AreEqual<NativeInt>(4, Length(r.Values)). NativeInt это Integer в 32-битной версии и Int64 в 64-битной. И System._DynArrayLength() возвращает NativeInt. - person Remy Lebeau; 02.08.2017
comment
@Remy: хорошо! Руди: все 3 решения работают как на Win32, так и на Win64. Единственное сомнение, которое остается, заключается в том, почему интерфейсы и реализации RTL list, list helper и container не были перенесены в NativeInt. Они внутренне основаны на массивах, но все методы по-прежнему ссылаются на целочисленные параметры емкости, количества и индекса :( - person Frazz; 03.08.2017