В общем, у меня проблема с выяснением того, как обрабатывать преобразования указателей в паскале. Если бы мне нужно было слово из моего указателя байта, я бы не сделал что-то вроде:
type WordPtr = ^Word;
var P1, P2 : ^Byte; w, byteoffset : word;
begin
P1:=SomeGetMemVar; byteoffset:=8;
w:=WordPtr(@P1^[byteoffset])^; { invalid qualifiers at the [ }
w:=WordPtr(P1[byteoffset])^; { invalid qualifiers at the [ }
w:=WordPtr(P1+byteoffset)^; { type mismatch }
end;
По-видимому, нет, потому что это не работает, как показано в комментариях.
Как заставить это работать на Паскале? С будет:
uint16_t byteoffset=8;
uint8_t* P1=(uint8_t*) malloc(1000);
uint16_t w;
w=*((uint16_t*) (P1+byteoffset)); // method 1
w=*((uint16_t*) (&P1[byteoffset])); // method 2
Спасибо!
Если ваш пример - это то, что вы пытаетесь сделать, то есть просто извлечь один байт слова, вам не нужно выполнять все эти манипуляции с указателем. Попробуй это:
uses System.SysUtils;
type WordPtr = ^WordRec;
var w: word;
p1: WordPtr;
begin
p1=GetSomeMemVar;
w:=p1.Hi;
end;
WordRec — это запись с двумя байтовыми полями в пространстве слова, так что вы можете получить доступ к каждому байту слова. В SysUtils также есть LongRec и Int64Rec, и все они имеют варианты частей, так что вы можете получить доступ к отдельным байтам или отдельным словам и т. д. или рассматривать их как массивы. И вы всегда можете создать свои собственные подобные записи.
Если вы хотите продолжить работу с указателями, см. https://docwiki.embarcadero.com/RADStudio/Sydney/en/Pointer_Math_%28Delphi%29
Чтобы обрабатывать указатели как массивы, убедитесь, что включена функция {$POINTERMATH ON}. Это уже для PByte (не используйте ^Byte напрямую), но не для большинства типов указателей по умолчанию.
Попробуйте еще что-нибудь вроде этого:
{$POINTERMATH ON}
var
P1 : PByte;
w, byteoffset : Word;
begin
P1 := SomeGetMemVar;
byteoffset := 8;
w := PWord(@P1[byteoffset])^;
//or:
w := PWord(P1+byteoffset)^;
end;
В качестве альтернативы используйте Move() вместо указателей приведения:
var
P1 : PByte;
w, byteoffset : Word;
begin
P1 := SomeGetMemVar;
byteoffset := 8;
Move(P1[byteoffset], w, SizeOf(w));
//or:
Move((P1+byteoffset)^, w, SizeOf(w));
end;
Для более старых компиляторов, которые не поддерживают {$POINTERMATH}, вы можете привести тип к PAnsiChar (который всегда поддерживал математику указателя по умолчанию):
var
P1 : PByte;
P2: PAnsiChar;
w, byteoffset : Word;
begin
P1 := SomeGetMemVar;
P2 := PAnsiChar(P1);
byteoffset := 8;
w := PWord(@P2[byteoffset])^;
//or:
w := PWord(P2+byteoffset)^;
end;
Или просто увеличьте указатель PByte вручную:
var
P1, P2 : PByte;
w, byteoffset : Word;
begin
P1 := SomeGetMemVar;
byteoffset := 8;
P2 := P1;
Inc(P2, byteoffset);
w := PWord(P2)^;
end;
Это немного отличается в зависимости от версии. Непосредственная причина ошибки в том, что ^Byte не является массивом. Вместо этого вы можете объявить type TByteArray = array[0..65535] of byte;, а затем type PByteArray = ^TByteArray;, а затем использовать PByteArray вместо ^Byte выше. При этом ваша первая попытка должна скомпилироваться.