关于指针地址操作(50分)

小心Delphi的对象,其实Delphi的对象全部是指针,例如我们最熟悉的Form,当我们调用
Form1.Edit1.Text时,其实Form1是指针,Edit1也是指针,只是大家可能没有注意罢了
也许有人会说,不对指针的调用应该是用Pointer^.Member,不错,是这样的,只不过
Form1和Edit1是Class,它是用指针实现,具有指针所有特性,但毕竟定义为Class,所以只能
用Form1.Edit1.Text来调用,而不能用Form1^.Edit^.Text,在这里还有一个有趣的现象,可
能大家没有注意,我们不可以用Edit1^.Text,但是如果我们定义
var pEdit: ^TEdit;
pEdit1 := @Edit1;
结果会怎样呢?如果我们要给Edit1.Text赋值'123',那么我们如何使用pEdit?
大家都会说,简单pEdit1^.Text := '123'就可以了,不错确实是这样,不过大家可以再试
一下,用pEdit1.Text := '123',看看会怎样,没想到吧,结果一样,这就是为什么说
对象就是指针的例子之一,在Delphi中,没有C++那样的对象变量,只要是对象,都用指针
实现。结构变量和结构指针的用法也有类似的地方,不过Record的变量,不是由指针来实
现的,所以大家用Move函数特别小心,比方说
var pSource,pDest:pChar;
len: integer;
.......................//一些代码
Move(pSource,pDest,len)
//错误
Move(pSource^,pDest^,len)
//正确
小心呀,要不然,你死了都不知道在那里死的
 
to creation-zy
to 2373088
二位认为Move函数是传值方式,那就错了
我们能看到以下代码
var pSource,pDest:pChar;
len: integer;
.......................//一些代码
Move(pSource,pDest,len)
//错误
Move(pSource^,pDest^,len)
//正确
看起来确实好像是传值,而不是传地址,但是各位别忘了,这不是C,C++,而是Delphi
Object Pascal,所以,绝不能从函数调用的方法判断是传值还是串地址!!必须看函数的
定义,只有定义才能说明是传值还是传地址,再说一遍,这不是C,C++!!
我们看到的函数定义是这样的
procedure Move(const Source
var Dest
Count: Integer);
从定义上看,很清楚,Dest是传地址,而不是传值,那么Source呢,其实大家不太清楚
这里的Const修饰符有两个含义,第一个大家都知道就是Source一常量方式在函数体内,
不可以改变它的值,第二个可能知道的人不多,那就是Source的传递方式和Dest一样,
是传地址!也就是说const和var一样,都是传地址,只不过一个在函数内不允许修改,
另一个是修改后影响调用的变量值
所以Move是传地址,而恰恰不是传值!
 
>>来自:2373088, 时间:2001-10-24 16:17:00, ID:688975
>>Move应该是按值传递,而不是按地址传递。creation-zy, 不知我说的对不对?
>>至于您所说的传值方式能否详细告知?
>>例一: 例二:
>> New(pTmp)
New(pTmp);
>> new(pTmp1)
new(pTmp1);
>> StrCopy(pTmp,'1')
pTmp := '1';
>> Move(pTmp^,pTmp1^,SizeOf(pTmp))
Move(pTmp^,pTmp1^,SizeOf(pTmp));
>> Dispose(pTmp)
Dispose(pTmp);
>> Dispose(pTmp1)
Dispose(pTmp1);
>>其中pTmp和pTmp1均为PChar类型,但例二释放指针时会出现异常,这是为什么。

上面的代码是错误的,例一,例二都是错误的,看看楼上我的的分析,我想你能明白为什么
首先用 new 在这里完全错误
其次 Move 函数用法错误
 
to edymill:
>>我想把整個LstTem Copy 到別外一個LstTemOther;當然不是用這個LstTemOther指向
>>同一個地址。修改LstTem 不會引響LstTemOther。這樣當然可以用上面的方法Loop lstTem
>>用它的每一個值賦給LstTemOther。這樣很煩的。不知道 能不能copy 內存實現?所以想
>>請問各位大俠!

呵呵,你只能这样了
LstTemOther.Clear;
for iLoop:= 0 to LstTem.Count-1 do LstTemOther.Add(LstTem.Items[iLoop]);
 
to Jedei:
用你那种方式把LstTem的数据Copy到LstTemOther中去,你会发现改变LstTem的一个节点数据,
LstTemOther中的相应节点也会改变,因为TList的节本来只是数据的指针。
必须每个节点的记录重新New,然后把LstTem的每个节点的数据Copy过来!
 
to Jedei:
樓上的說的對,這是指向同一地址的,你這樣就是
lstTemOther := lstTem;一樣的;
to aizb :
如果我的Tlist有很多item,並且有很多級,copy 一個Tlist讓我寫了一大堆代碼,
很煩的,不過現我隻有這樣做了,不知另外有沒有更好的法子,謝了
 
GetMem() //分配内容
FreeMem()//Release memory
copyMemory() //内存COPU
strcpy or strlcpy 只适合于COPY字串之类,遇到#0 会自动结束
copyMemORY 则不会 ,
如 分别用
var
a,b,c : integer ;
begin
a := 1024 ;
b :=0 ;
c :=0;
strlcpy(@b,a,4);
copymemory(@c,a,4);
//结果是 a =0 , c = 1024
end

 
New(pTmp);
New(pTmp1);
pTmp^:='1'
//这里
Move(ptmp^,pTmp1^,sizeof(pTmp1));
Dispose(pTmp1);
Dispose(pTmp);
 
数据的基本单位是byte,字符只不过是一种特例,这一点高级语言做的都很不好,而汇编语言
在处理地址、传值方面既简单又高效,还是用汇编吧!
 
to SS2000:
我就是因为这个问题所提不得已采用汇编实现:
asm
mov edx,PBuf
mov eax,PSrcBuf
mov ecx,len
call move
end;
这比什么Move(P0^,P1^,Len)虽然长一点,但清晰很多,一目了然。


to 张一健:
>>new 会执行构造函数
有没有搞错?Object Pascal中的New过程什么时候又变成C++中的New函数了??
你试一试:
procedure TForm1.Button1Click(Sender: TObject);
var
A:TForm1;
begin
New(A)
//你能编译过去??!!
end;
Object Pascal中的类的类存分配一般是由该类的Create方法实现,如: A:=TForm1.Create(Self);
而New仅用指定类型的指针分配内存,如:
var
A:^TPoint;
begin
New(A);
end;


>>例二释放指针时会出现异常,这是为什么?
var
pTmp,pTmp1:pChar;
begin
New(pTmp);
new(pTmp1);
pTmp:= '1'
//同志,这里是不是应该改为 pTmp^:='1'
呢?? (奇怪,编译器竟然没有警告...)
Move(pTmp^,pTmp1^,SizeOf(pTmp))
//还有这里——你移动的是指针所指向的内容
//而不是指针本身, 因该用 Move(pTmp^,pTmp1^,SizeOf(pTmp^))
——SizeOf(pTmp^) 明白?
//对任何类型的指针直接进行SizeOf运算,结果都是4!
Dispose(pTmp);
Dispose(pTmp1);
end;


to masm:
>>还是用汇编吧!
高见呀!——用钢筋混凝土造房子怎么可能随心所欲呢?——还是一个分子一个分子的慢慢搭合算!
 
asm
pusha
mov esi,p1
mov edi,p2
mov ecx,len//双字长度
repnz movsd
end;
就这么简单!Delphi和C能有这么高的效率,最主要的原因是其内部的很多过程都是直接由
汇编写的。国外已经有面向对象的汇编语言,巨爽!!
 
上面的汇编最后漏了一句
popa
抱歉!
 
哇,讨论得这么激烈,同志们,俺也正在学,现学现卖,补充两句:
几个寄存器的用途
对于一般的procedure ,function有:
在入口: //1
eax 保存procedure or function的第一个参数值(如果存在的话)
ebx 保存procedure or function的地址 ***
ecx 保存procedure or function的第三个参数值
edx 保存procedure or function的第二个参数值
在出口: //2
eax 对于function是保存结果;对于procedure一般是保存相关的自定义错误代码
ebx 仍是保存procedure or function的地址 ***

/////////////////////
对于对象的方法:
在入口: //3
eax 保存parent对象的地址
ebx 同上
ecx 保存第二个参数值
edx 保存第一个参数值
在出口:
同//2
 
var
t:string;
p:^byte;
...
t:='12345';
p:=@t;
这样是不能得到字符串t的正确的内存地址的,只能得到指向t的指针的地址,而你自作聪明
地把这个地址的值赋给另外一个已经定义的指针变量时(尽管数学上这是正确的),编译器
就会告诉你数据类型不匹配,而在汇编上,这是最最常用编程方法,
mov esi,@t
mov eax,[esi]
太简单了!所有现代OOP语言离开了汇编真的寸步难行!
 
>asm
> mov edx,PBuf
> mov eax,PSrcBuf
> mov ecx,len
> call move
>end;
>这比什么Move(P0^,P1^,Len)虽然长一点,但清晰很多,一目了然。
to creation-zy:
你能用汇编实现,真是厉害,不过你说用汇编“清晰很多,一目了然”,在下不敢苟同
在下斗胆问问各位,大家认为是汇编清楚明了,还是Move函数简单明了。

>var
>t:string;
>p:^byte;
>...
>t:='12345';
>p:=@t;
>这样是不能得到字符串t的正确的内存地址的,只能得到指向t的指针的地址,而你自作聪明
>地把这个地址的值赋给另外一个已经定义的指针变量时(尽管数学上这是正确的),编译器
>就会告诉你数据类型不匹配,而在汇编上,这是最最常用编程方法,
>mov esi,@t
>mov eax,[esi]
>太简单了!所有现代OOP语言离开了汇编真的寸步难行!

to masm:
对于你的见解,我不知道你是真的这么认为,还是误导大家,上面的分析没错
var
>t:string;
>p:^byte;
>...
>t:='12345';
>p:=@t;
编译器会报错,可是你把最后一句改为 p:=PChar(t)看看,当然,p的定义可以改为PChar
p: PChar;
你可别告诉我PChar和^byte有本质的区别!!!
另外,抱歉的告诉你
mov esi,@t
mov eax,[esi]
编译正确,可是结果却是错误的,看来你对delphi不是很精通
我10年前编程,也只有编类似病毒的程序用汇编,用TC时有时用嵌入汇编,到现在,当然是不用汇编,
如果有人在Windows下编程用汇编,我向他致敬:如此固执、顽固、跟不上形势,还不想被淘汰
还用汇编写Windows程序!!只是不知您“老”人家用的是什么编译器???不知道我一天
能编出来的程序,您“老”人家是否能在一年内用汇编编出来?呵呵,可能您“老”人家精通
汇编,不用一年,用一个月就可以编出来了!!呵呵呵呵
>>>"所有现代OOP语言离开了汇编真的寸步难行!" masm,你说这句话是在做什么?(臭不可闻)
 
不想和你争论什么,去看看delphi使用的use单元吧!
别让那些大型的开发程序晃了眼,除非是一本正经地,完全不在乎效率的公文式的程序,否则必须使用汇编!
去看看windows下的oop汇编!又一个老外的创造!你能马上写出来一个只有关闭按钮且失效的
窗体吗?哈!
 
“去看看delphi使用的use单元吧!”

to masm宏汇编先生/小姐(不知你是那个版本,6.0还是7.0或别的?):

我看得比你多!!
请问,这么多use单元中,你能找出几个是汇编写的?
所占百分比又是多少?不要找出一个单元里有汇编,
你就以为所有单元是汇编写的!一叶障目,不知森林!
“只有关闭按钮且失效的窗体”,你要吗?如果用delphi写
或VC++写,3秒钟给你,如果用VB写10秒钟给你,不知道
是否够快?能不能达到你的“马上”要求?再说了这样的东西
有用吗?我们是做应用开发的,不是做操作系统的,你是做
操作系统的吗?在什么公司呀?什么操作系统?非要用汇编!
还要全部用汇编!!要知道Windows的99.99%的代码也不是汇编!
不是汇编不好,是你过时了,虽然我也是从DOS走过来的,
用汇编、C用得很多,但我还算跟住了潮流,及时的抛弃了DOS,
转入了Windows的开发,当然也抛弃了汇编,不过并不是所我
不懂汇编,只是不用汇编(在我精通汇编的时候(90年,还没有
Windows,DOS的天下),不知阁下在做什么?是否也用汇编),
即使是在那个时候,我也只有在单片机和特殊的情况下用汇编,
因为没有必要,完全没有!! 我查看过编译器生成的汇编代码,
虽然有些地方还可以优化,但是,你能为了提高1%的效率而
增加100%的工作量吗!!如果你愿意,我无话可说,因为,
我无法跟一个不正常的人讨论问题!!

最后说一句,如果这个论坛用汇编写,不知masm用多少时间能
做出来! 任何语言都不是万能的,你会的语言越多,视眼才能
开阔,才不会极端!试问,看到我这个贴子的同仁们,你们有几
个在用汇编开发Windows程序,masm你用汇编开发过什么Windows程序,
能否一观,看看比用Delphi开发的好到什么程度!!
 
to SS2000:
的确,我的方法看起来没有任何优势。我之所以这样做,关键原因在于Delphi的传值方式容易让人混淆,
我不希望我的代码过几天再看的话会产生误解。
procedure Move( const Source
var Dest
count : Integer );
asm
{ ->EAX Pointer to source }
{ EDX Pointer to destination }
{ ECX Count }

在这里,传进来的参数明明是指针,但是我们在调用的时候给出的却必须是指针所指向的对象!
在Delphi中,加了const和var修饰之后,容易使人误解。
你看看:FileRead function ——Delphi自带的例子都弄错了! (lid=585070)
如果直接传递指针的话...
 

Similar threads

X
回复
0
查看
772
xalion
X
S
回复
0
查看
645
SUNSTONE的Delphi笔记
S
S
回复
0
查看
655
SUNSTONE的Delphi笔记
S
顶部