首页
社区
课程
招聘
指针问题该如何解决?
2006-2-14 12:51 5489

指针问题该如何解决?

2006-2-14 12:51
5489
Delphi只有PChar类型的指针才能和整数进行运算
如果定义了下面的指针类型
lpImgData : ^BITMAPINFOHEADER;
下面的代码将无法编译通过。
而定义的类型又不能被改,该如何解决呢?

lpImgData : ^BITMAPINFOHEADER;
ImgSize : DWORD;
i : Interger;

for i := 0 to ImgSize do
begin
   (lpImgData + i)^ := 255 - (lpImgData + i)^;
end;

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
点赞7
打赏
分享
最新回复 (6)
雪    币: 238
活跃值: (326)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
gzgzlxg 11 2006-2-16 18:34
2
0
BITMAPINFOHEADER是结构,当然不能进行这样的操作,
你可以将这个结构的地址指向一个 PChar ,然后就可以如你这样的操作了.
如果是我, 直接加几句汇编进去, 又快又简单.
雪    币: 1540
活跃值: (2787)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
limee 2006-2-16 21:57
3
0
能把代码给贴出来吗?

最初由 gzgzlxg 发布
BITMAPINFOHEADER是结构,当然不能进行这样的操作,
你可以将这个结构的地址指向一个 PChar ,然后就可以如你这样的操作了.
如果是我, 直接加几句汇编进去, 又快又简单.
雪    币: 238
活跃值: (326)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
gzgzlxg 11 2006-2-17 00:45
4
0
实在不能理解你这样做的目的,代码很简单,如下
  procedure FillBitmapInfoHeader(pImgData: PBitmapInfoHeader; ImgSize:Integer);
  procedure FillBitmapInfoHeader1(lpImgData: PBitmapInfoHeader; ImgSize:Integer);
implementation

这个是通过 PChar 来实现
procedure FillBitmapInfoHeader(pImgData: PBitmapInfoHeader; ImgSize:Integer);
var
  lpImgData: PChar;
  i : Integer;
begin
  lpImgData := PChar(pImgData);
  for i := 0 to ImgSize - 1 do
    PByte(lpImgData + i)^ := 255 - PByte(lpImgData + i)^;
end;
这个是通过汇编来实现
procedure FillBitmapInfoHeader1(lpImgData: PBitmapInfoHeader; ImgSize:Integer);
asm
    pusha
    mov esi, eax
    mov ecx, edx
  @1:
    lodsb
    mov ah, 255
    sub ah, al
    mov [esi - 1], ah
    dec cx
    loop @1
    popa
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  ImgData : TBitmapInfoHeader;
  ImgSize : Integer;
begin
  ImgSize := SizeOf(TBitmapInfoHeader);
  FillBitmapInfoHeader1(@ImgData, ImgSize);
  FillBitmapInfoHeader(@ImgData, ImgSize);
end;
雪    币: 215
活跃值: (40)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
蓝色光芒 1 2006-2-17 22:41
5
0
//直接用指针来实现
procedure FillBitmapInfoHeader(pImgData: PBitmapInfoHeader; ImgSize:Integer);
var
  i : Integer;
begin
  for i := 0 to ImgSize - 1 do
    PByte(Pointer(DWORD(pImgData) + i))^ := 255 - PByte(Pointer(DWORD(pImgData) + i))^;
end;
雪    币: 238
活跃值: (326)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
gzgzlxg 11 2006-2-18 02:48
6
0
首先声明,我不是来钻牛角尖,抬杠子的,我的目的是不要误导提问的朋友,按你的写法即不省时间,也不提高运行速度,只是带来错误的隐患.

最初由 蓝色光芒 发布
//直接用指针来实现
procedure FillBitmapInfoHeader(pImgData: PBitmapInfoHeader; ImgSize:Integer);
var
i : Integer;
begin
for i := 0 to ImgSize - 1 do
PByte(Pointer(DWORD(pImgData) + i))^ := 255 - PByte(Pointer(DWORD(pImgData) + i))^;
end;

关于指针问题的探讨:
在语句
    PByte(Pointer(DWORD(pImgData) + i))^ := 255 - PByte(Pointer(DWORD(pImgData) + i))^;
    Pointer 是多余的,可以去掉.
写成如下格式:
    PByte(DWORD(pImgData) + i)^ := 255 - PByte(DWORD(pImgData) + i)^;
这两个语句编译后产生的代码完全相同.

表面上看这个语句似乎是正确的,其实这个语句中使用 DWORD 是错误的,应该使用 Integer;
使用 DWORD 编译器会出现如下警告:
[Warning] Unit1.pas(73): Combining signed and unsigned types - widened both operands
粗看似乎只是有符号数和无符号数的定义问题,其实问题远没有这么简单,我们来看看使用 DWORD 后产生的编译代码:

CODE:00401ACC FillBitmapInfoHeader3 proc near         ; CODE XREF: _TForm1_Button1Click+3Ap
CODE:00401ACC
CODE:00401ACC var_18          = dword ptr -18h
CODE:00401ACC var_14          = dword ptr -14h
CODE:00401ACC ImgSize1        = dword ptr -10h
CODE:00401ACC i               = dword ptr -0Ch
CODE:00401ACC ImgSize         = dword ptr -8
CODE:00401ACC pImgData        = dword ptr -4
CODE:00401ACC
CODE:00401ACC                 push    ebp
CODE:00401ACD                 mov     ebp, esp
CODE:00401ACF                 add     esp, 0FFFFFFF0h
CODE:00401AD2                 mov     [ebp+ImgSize], edx
CODE:00401AD5                 mov     [ebp+pImgData], eax
CODE:00401AD8                 mov     eax, [ebp+ImgSize]
CODE:00401ADB                 dec     eax
CODE:00401ADC                 test    eax, eax
CODE:00401ADE                 jl      short loc_401B23
CODE:00401AE0                 inc     eax
CODE:00401AE1                 mov     [ebp+ImgSize1], eax
CODE:00401AE4                 mov     [ebp+i], 0
CODE:00401AEB
CODE:00401AEB loc_401AEB:                             ; CODE XREF: FillBitmapInfoHeader3+55j
CODE:00401AEB                 mov     eax, [ebp+pImgData]
CODE:00401AEE                 xor     edx, edx
;======================= 这里产生错误代码也是垃圾代码 =========================
CODE:00401AF0                 push    edx                    
CODE:00401AF1                 push    eax
CODE:00401AF2                 mov     eax, [ebp+i]
CODE:00401AF5                 cdq
CODE:00401AF6                 add     eax, [esp+18h+var_18]
CODE:00401AF9                 adc     edx, [esp+18h+var_14]
CODE:00401AFD                 add     esp, 8
;==========================================================================
CODE:00401B00                 mov     cl, 0FFh
CODE:00401B02                 sub     cl, [eax]
CODE:00401B04                 mov     eax, [ebp+pImgData]
CODE:00401B07                 xor     edx, edx
;======================= 这里产生错误代码也是垃圾代码 =========================
CODE:00401B09                 push    edx
CODE:00401B0A                 push    eax
CODE:00401B0B                 mov     eax, [ebp+i]
CODE:00401B0E                 cdq
CODE:00401B0F                 add     eax, [esp+18h+var_18]
CODE:00401B12                 adc     edx, [esp+18h+var_14]
CODE:00401B16                 add     esp, 8
;==========================================================================
CODE:00401B19                 mov     [eax], cl
CODE:00401B1B                 inc     [ebp+i]
CODE:00401B1E                 dec     [ebp+ImgSize1]
CODE:00401B21                 jnz     short loc_401AEB
CODE:00401B23
CODE:00401B23 loc_401B23:                             ; CODE XREF: FillBitmapInfoHeader3+12j
CODE:00401B23                 mov     esp, ebp
CODE:00401B25                 pop     ebp
CODE:00401B26                 retn
CODE:00401B26 FillBitmapInfoHeader3 endp

编译器认为 pImgData 是 Qwrod 而不是 Dword, 所以对循环变量 i 进行处理, 将其扩展为 Qword, 使用 cdq 指令.但不知为何编译器扩展了 i 为Qword,却没有使用这个扩展的结果,显然你的写法把编译器弄糊涂了.

再看将 Dword 改为 Integer 以后产生的正确的编译代码:

CODE:00401B28 FillBitmapInfoHeader4 proc near         ; CODE XREF: _TForm1_Button1Click+45p
CODE:00401B28
CODE:00401B28 ImgSize1        = dword ptr -10h
CODE:00401B28 i               = dword ptr -0Ch
CODE:00401B28 ImgSize         = dword ptr -8
CODE:00401B28 pImgData        = dword ptr -4
CODE:00401B28
CODE:00401B28                 push    ebp
CODE:00401B29                 mov     ebp, esp
CODE:00401B2B                 add     esp, 0FFFFFFF0h
CODE:00401B2E                 mov     [ebp+ImgSize], edx
CODE:00401B31                 mov     [ebp+pImgData], eax
CODE:00401B34                 mov     eax, [ebp+ImgSize]
CODE:00401B37                 dec     eax
CODE:00401B38                 test    eax, eax
CODE:00401B3A                 jl      short loc_401B61
CODE:00401B3C                 inc     eax
CODE:00401B3D                 mov     [ebp+ImgSize1], eax
CODE:00401B40                 mov     [ebp+i], 0
CODE:00401B47
CODE:00401B47 loc_401B47:                             ; CODE XREF: FillBitmapInfoHeader4+37j
CODE:00401B47                 mov     eax, [ebp+pImgData]
CODE:00401B4A                 add     eax, [ebp+i]
CODE:00401B4D                 mov     dl, 0FFh
CODE:00401B4F                 sub     dl, [eax]
CODE:00401B51                 mov     eax, [ebp+pImgData]
CODE:00401B54                 add     eax, [ebp+i]
CODE:00401B57                 mov     [eax], dl
CODE:00401B59                 inc     [ebp+i]
CODE:00401B5C                 dec     [ebp+ImgSize1]
CODE:00401B5F                 jnz     short loc_401B47
CODE:00401B61
CODE:00401B61 loc_401B61:                             ; CODE XREF: FillBitmapInfoHeader4+12j
CODE:00401B61                 mov     esp, ebp
CODE:00401B63                 pop     ebp
CODE:00401B64                 retn
CODE:00401B64 FillBitmapInfoHeader4 endp

再看我原帖的语句:
procedure FillBitmapInfoHeader(pImgData: PBitmapInfoHeader; ImgSize:Integer);
var
  lpImgData: PChar;
  i : Integer;
begin
  lpImgData := PChar(pImgData);            //我在这里这样写是为了让提问题的朋友容易理解
  for i := 0 to ImgSize - 1 do
    PByte(lpImgData + i)^ := 255 - PByte(lpImgData + i)^;
end;

将这句改成如下形式,只是简单的合并同类项:

procedure FillBitmapInfoHeader5(pImgData: PBitmapInfoHeader; ImgSize:Integer);
var
  i : Integer;
begin
  for i := 0 to ImgSize - 1 do
    PByte(PChar(pImgData) + i)^ := 255 - PByte(PChar(pImgData) + i)^;
end;

这段程序编译后和上面使用 Integer 的结果完全相同, 但从阅读和理解显然比使用 Integer 来得好.

最后我们来欣赏汇编程序产生的代码:

CODE:00401A30 FillBitmapInfoHeader proc near          ; CODE XREF: _TForm1_Button1Click+19p
CODE:00401A30                 pusha
CODE:00401A32                 mov     esi, eax
CODE:00401A34                 mov     ecx, edx
CODE:00401A36
CODE:00401A36 loc_401A36:                             ; CODE XREF: FillBitmapInfoHeader+10j
CODE:00401A36                 lodsb
CODE:00401A37                 mov     ah, 0FFh
CODE:00401A39                 sub     ah, al
CODE:00401A3B                 mov     [esi-1], ah
CODE:00401A3E                 dec     cx
CODE:00401A40                 loop    loc_401A36
CODE:00401A42                 popa
CODE:00401A44                 retn
CODE:00401A44 FillBitmapInfoHeader endp

很明显,这段代码的运行速度最快的.
如果勤快一点, 将压栈语句改成
   push esi
   push ecx
   ......
   ......
   pop ecx
   pop esi
这样代码看起来长了,但实际运行更快,而且少占堆栈空间.
雪    币: 215
活跃值: (40)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
蓝色光芒 1 2006-2-23 15:08
7
0
游客
登录 | 注册 方可回帖
返回