Два из этих типов похожи (фактически идентичны). Третий нет.
TArray объявляется как " Массив байтов ", как и TBytes . Однако вы пропустили еще один очень актуальный тип, TByteArray (тип, на который ссылается PByteArray ).
Будучи указателем на TByteArray , PByteArray , строго говоря, является указателем на статический байтовый массив, а не на динамический массив (который все остальные типы байтовых массивов). Он набирается таким образом, чтобы разрешить ссылку на смещения от этого базового указателя с использованием целочисленного индекса. И обратите внимание, что это индексирование ограничено 2 ^ 15 элементами (0..32767). Для произвольных смещений байтов (> 32767) от некоторого базового указателя PByteArray не годится:
var
b: Byte;
ab: TArray<Byte>;
pba: PByteArray;
begin
SetLength(ab, 100000);
pba := @ab; // << No cast necessary - the compiler knows (magic!)
b := pba[62767]; // << COMPILE ERROR!
end;
т.е. приведение массива байтов или TArray к PByteArray потенциально может привести к проблемам, когда массив имеет> 32K элементов (и указатель передается на некоторый код, который пытается получить доступ ко всем элементам). Преобразование к нетипизированному указателю, конечно, позволяет избежать этого (при условии, что «получатель» указателя затем соответствующим образом обрабатывает указатель на доступ к памяти).
НО, в будущем ничего из этого вряд ли изменится, это всего лишь следствие деталей реализации, которые давно применяются в этой области. Представление синтаксически сахаросодержащего объявления универсального типа представляет собой kipper rouge .