delphi 如何使用Pascal指针访问不同的数据类型?

k4emjkb1  于 2023-02-19  发布在  其他
关注(0)|答案(2)|浏览(153)

一般来说,我在pascal中处理指针转换时会遇到一些问题,如果我想从字节指针中得到一个字,我会不会做一些类似这样的事情:

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;

显然不是,因为它不像评论中显示的那样工作。
我怎样用Pascal来实现呢?C应该是:

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

谢谢!

mwyxok5s

mwyxok5s1#

为了将指针视为数组,请确保{$POINTERMATH ON}已启用。PByte已经启用了{$POINTERMATH ON}(不要直接使用^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;
46scxncf

46scxncf2#

如果你的例子就是你想要做的,也就是简单地提取一个单词的一个字节,你就不需要做所有的指针操作。

uses System.SysUtils;
type WordPtr = ^WordRec;
var w:  word;
    p1: WordPtr;
begin
  p1=GetSomeMemVar;
  w:=p1.Hi;
end;

WordRec是一个记录,在一个单词的空间里有两个字节字段,这样你就可以访问单词的每个字节。SysUtils还有LongRecInt64Rec,它们都有变体部分,这样你就可以访问单独的字节或单独的单词等,或者把它们当作数组。你总是可以创建自己的类似记录。
如果要继续使用指针,请参见https://docwiki.embarcadero.com/RADStudio/Sydney/en/Pointer_Math_%28Delphi%29

相关问题