有朋友学过Turbo pascal吗,有一个简单问题想向您请教 ( 积分: 100 )

W

wangsea

Unregistered / Unconfirmed
GUEST, unregistred user!
一段代码如下,估计是Turbo pascal写的:
Unit BiosCrt;
interface
usesdo
s;
var BiosWriteMode : byte;
{Bios write mode to use for TFDD}
BiosTextAttr : byte;
{Bios text attribute byte}
BiosStartAttr : byte;
{Original startup attr}
LastBiosMode : byte;
{last Bios screen mode in use}
LastBiosWidth : byte;
{last Bios screen width used}
LastBiosPage : byte;
{last Bios screen page used}
.....
procedure BiosTextColor(FColor:integer);
{Set text foreground color}
inline(
$58 { pop AX}
/$24/$0f { and AL,$0F}
/$8A/$26/>BiosTextAttr { mov AH,[>BiosTextAttr]}
/$80/$E4/$F0 { and AH,$F0}
/$08/$E0 { or AL,AH}
/$A2/>BiosTextAttr);
{ mov [>BiosTextAttr],AL}

这里这个变量BiosTextAttr在inline中的引用是/$8A/$26/>BiosTextAttr
俺在TMT pascal中通不过,请教其它的写法。
 
一段代码如下,估计是Turbo pascal写的:
Unit BiosCrt;
interface
usesdo
s;
var BiosWriteMode : byte;
{Bios write mode to use for TFDD}
BiosTextAttr : byte;
{Bios text attribute byte}
BiosStartAttr : byte;
{Original startup attr}
LastBiosMode : byte;
{last Bios screen mode in use}
LastBiosWidth : byte;
{last Bios screen width used}
LastBiosPage : byte;
{last Bios screen page used}
.....
procedure BiosTextColor(FColor:integer);
{Set text foreground color}
inline(
$58 { pop AX}
/$24/$0f { and AL,$0F}
/$8A/$26/>BiosTextAttr { mov AH,[>BiosTextAttr]}
/$80/$E4/$F0 { and AH,$F0}
/$08/$E0 { or AL,AH}
/$A2/>BiosTextAttr);
{ mov [>BiosTextAttr],AL}

这里这个变量BiosTextAttr在inline中的引用是/$8A/$26/>BiosTextAttr
俺在TMT pascal中通不过,请教其它的写法。
 
inline(
$58 { pop AX}
/$24/$0f { and AL,$0F}
/$8A/$26/>BiosTextAttr { mov AH,[>BiosTextAttr]}
/$80/$E4/$F0 { and AH,$F0}
/$08/$E0 { or AL,AH}
/$A2/>BiosTextAttr);
{ mov [>BiosTextAttr],AL}
inline是什么? pascal中的汇编吗?
 
不同编译器的内联汇编码是不同的。所以不同的版本的pascal编译器编译同一个程序时可能有的不能通过。这一点在c++编译器市场中是最明显的。上面的是内嵌机器码。可能不行哟
 
除了有>BiosTextAttr 形式的通不过外其余的内嵌汇编都可通过,所以问这个呀!
这类型式的代码在以前的老turbo pascal有许多,不找到方法无法重用这些代码。所以请求知道的朋友帮忙呀。
 
你看转成delphi格式的能否编译成功
asm
汇编代码...........
end;
 
楼上的朋友,inline 与 asm 是两种异曲同工的用法,都能实现内嵌汇编,delphi本身都支取持。但就俺的目的而言,如果改成asm 形式代价就大了(因为并不是只有这一个是用inline的呀).所以只求 >BiosTextAttr 在inline中的其它写法。
不考虑编译器的不同,把你知道的写法写出来吧。
 
指针的指针而已,很简单.楼住居然用AllocMem给动态数组分配内存.晕死
char **pattern;
应该翻译成这个样子
var
S:String = 'abcdefg';
procedure TForm6.Button1Click(Sender: TObject);
Type
TT=array[0..0]of ^pchar;
{
因为数组只有一个元素,等价于TT=^PChar;
但为了使用数组特性,所以声明成数组.可以进行越界访问
}
Const
aCount = 5;
var
mytest: ^TT;
I:Integer;
begin
mytest:=AllocMem(sizeof(pchar)*aCount);
S := '123456';
{因为数组只有一个元素,用常量做下标会报越界错误.
可以加编译开关.在这段代码中暂时关闭掉越界检查
也可以用变量做下标的方式.编译器就没有办法做越界检查了
}
I:=0;
mytest:= @S[1];
I := 1;
mytest:= @S[2];
ShowMessage(format('mytest的地址是$%s',[IntToHex(Integer(mytest),2)]));
for I := 0 to aCount - 1do
begin
ShowMessage(Format('第%d个成员的地址是$%s',[I,IntToHex(Integer(mytest),8)]));
end;

Freemem(mytest,sizeof(pchar)*aCount);
end;
 
非常感谢wr960204,最后一个问题:
如果采用您的方法用AllocMem申请内存后,又多次使用AllocMem申请其它的内存块,访问时会不会出错?(因为不是申请使用后就立即使用,使用完即释放,而且访问的方法是越界,所以担心这个)
 
to wr960204:
好象这样定义还是有问题,试试在代码中改变一下s,结果就出不正确了.
var
S:String = 'abcdefg';
procedure TForm1.Button5Click(Sender: TObject);
Type
TT=array[0..0]of ^pchar;
{
因为数组只有一个元素,等价于TT=^PChar;
但为了使用数组特性,所以声明成数组.可以进行越界访问
}
Const
aCount = 5;
var
mytest: ^TT;
I:Integer;
begin
mytest:=AllocMem(sizeof(pchar)*aCount);
S := '123456';
{因为数组只有一个元素,用常量做下标会报越界错误.
可以加编译开关.在这段代码中暂时关闭掉越界检查
也可以用变量做下标的方式.编译器就没有办法做越界检查了
}
I:=0;
mytest:= @S[1];
I := 1;
//越界访问
mytest:= @S[2];
ShowMessage(format('mytest的地址是$%s',[IntToHex(Integer(mytest),2)]));
ShowMessage('mytest的值是:'+Pchar(mytest^));
//显示123456
for I := 0 to aCount - 1do
begin
ShowMessage(Format('第%d个成员的地址是$%s',[I,IntToHex(Integer(mytest),8)]));
end;

s:='abcdefg';
//改变一下s试输出
ShowMessage('mytest的值是:'+Pchar(mytest^));
//显示为1234
Freemem(mytest,sizeof(pchar)*aCount);
end;
 
看来楼主对Delphi机制还是不了解啊.晕死!
String是生存期自管里的,用计数器管理生存期的.当内容被改变的时候会重新分配内存,地址也就变化了.你的指针指向的是原来的被释放掉的String的内容当然出错.
这里你可以用静态数组.
先补习一下Strng的知识吧.两个String用:=草做的时候不会分配内存.两个String指向一个内容.这个内容的计数器加1.当内容变化的时候才重新分配内存.同时计数器减1.当计数器变为0的时候会被垃圾回收.
所以当内容发生变化的时候String的内存地址不是固定的.
动态数组也是一样的.
所以如果内容会经常变动的时候楼主可以用静态数组.
再补充一下.我只所以把代码中的S声明成全局的是鉴于Delphi的代码优化.如果S是局部变量mytest:= @S[2];以后再没有使用到S,S会被优化掉.指针所指的内容也没什么意义了.
打这么多字手指要累断了.补充了这么多知识,楼主是不是要交学费啊.哈哈
 
谢谢wr960204给偶补课,偶的基础就是不好,wr960204费心啦,谢谢!
现在的问题是pattern是一段Buffer的指针,数组大小不定,所以不能申明为静态数组.
偶还是贴出原来的的C代码,谢再帮偶看看,该如何定义这个char **pattern;
当然,用delphi的方法处理这个单元不一定象C中这么做,但偶想贴近原意改写成delphi的
以便更好地贴近原代码.(用setlength是可以,但看代码malloc也行的呀,为何改写成
delphi的就不成功了呢?偶就想知道pattern这个缓冲区如何用AllocMem来申请)

char **pattern;
//开的缓冲,在其它单元处理
int pattern_count;
void GetPatterns()
{
HANDLE hService;
CHAR achKey[MAX_PATH];
DWORD i;
DWORD retCode;
int Nohide = 1;
DWORD SubKeyNum = 0;
pattern_count = 0;
if(RegOpenKeyEx(
HKEY_LOCAL_MACHINE, // handle to open key
"SYSTEM//ControlSet001//Services", // subkey name
NULL, // reserved
KEY_ALL_ACCESS,// security access mask
&hService // handle to open key
) != ERROR_SUCCESS)
{
printf("sorry %d/n",GetLastError());
return;
}
RegQueryInfoKey( hService,
NULL,
NULL,
NULL,
&SubKeyNum,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL);
//Before itdo
n't work well , because i set the wrong premission of HKEY
//KEY_ALL_ACCESS is needed
if(SubKeyNum == 0)
{
printf("SubKey's Number is NULL, it's too strange./n");
return;
}
pattern = malloc(sizeof(char *) * SubKeyNum );
for (i = 0, retCode = ERROR_SUCCESS;
retCode == ERROR_SUCCESS;
i++)
{
retCode = RegEnumKey(
hService, // handle to key to query
i, // index of subkey to query
achKey, // buffer for subkey name
MAX_PATH // size of subkey name buffer
);

if (retCode == (DWORD)ERROR_SUCCESS)
{
//What i add to get pattern Services Table.
pattern[ pattern_count ] = strdup ( achKey ) ;
pattern_count++;
}

}
CloseHandle(hService);
}
 
楼主,这个wr960204是个半吊子,手下带了几个菜鸟就不知道自己是谁了,相信自己你比他强,就是delphi不如他熟悉而已。
char **pattern;就是一个字符串数组,楼主你用TStringList很方便啊,pattern_count这个变量都不需要。
如果要模仿C,用动态数组就可以了。
var PP:array of Pchar;
 
看看下面这段应该可以用进去。
procedure TForm1.Button1Click(Sender: TObject);
var i:integer;
P:pchar;//P是字符串
PP:array of Pchar;//PP是字符串数组,就是一个指针数组
s:string;
begin
//添加一个字符串
P:=allocmem(10);
P^:='1';
(P+1)^:='2';
setlength(PP,high(PP)-low(PP)+2);//动态数组长度加1
PP[high(PP)]:=P;//加入数组
//再添加一个字符串
P:=allocmem(10);
P^:='a';
(P+1)^:='b';
setlength(PP,high(PP)-low(PP)+2);//动态数组长度加1
PP[high(PP)]:=P;//加入数组
//再添加一个字符串
P:=allocmem(10);
P^:='A';
(P+1)^:='B';
setlength(PP,high(PP)-low(PP)+2);//动态数组长度加1
PP[high(PP)]:=P;//加入数组

//用String显示PP字符串数组要小心不能用赋值,一赋值就改变指针指向
setlength(s,10);//先给String分配长度
for i:=low(PP) to high(PP)do
begin
copymemory(@s[1],PP,2);//拷贝内存
showmessage(s);
end;

//释放
for i:=high(PP) to low(PP)do
freemem(PP);
end;
 
谢谢两位老大的帮助,偶多做了几个试验,得出如下结论,基本上可以认为是编译器的不同处理不同.
{
char **pattern;
1:如果定义成 mytest:array of ^pchar,
由于AllocMem()返回的是一个指向所分配的地址指针,只管理其指定的组员的内存分
配,所以只分配了组元的内存地址.而mytest组元的类型是一个^pchar,其类型其实
是不确定的(^Pchar,指向Pchar类型(指向char型)的指针,是指针的指针,所以其类型
不确定),编译器无法帮助您申请其它的内存,所以就需要手动为其所指的内容分配空
间(还需申请另一内存块,或将某个内存地址赋给它),如果是申请的内存就需要用户来
处理组元所指空间的分配与释放,如果是传址,则不需要(由编译器管理)
2:定义成 mytest:array of string
此时mytest组元的类型是string,是一个明确的类型,则由编译器本身来处理其空
间的分配与释放,下面两个例子分别使用setlength与AllocMem来实现char **pattern;
从代码上看很相似,应该可看作是使用AllocMem来定义char **pattern;正确的作法.
}
procedure TForm1.Button1Click(Sender: TObject);
type
Mytest=array[0..0] of String;
var
aa:^Mytest;
i:integer;
begin
aa:=AllocMem(sizeof(pchar)*5);
For i:=0 to 4do
//即使是越界编译器也不允许你越过AllocMem申请的内存,所以i<5
begin
aa:='输出缓冲区中组元的内容:'+inttostr(i);
Memo1.Lines.Add(aa);
end;
Freemem(aa,sizeof(pchar)*5);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
Mytest:array of String;
i:integer;
begin
setlength(Mytest,sizeof(pchar)*5);
For i:=0 to 4do
begin
Mytest:='输出缓冲区中组元的内容:'+inttostr(i);
Memo1.Lines.Add(Mytest);
end;
setlength(Mytest,0);
end;

如果没有其它意见,偶晚上结贴.
 
再次感谢各位的帮助!
 
我确实是个半吊子.Delphi还算熟悉.C/C++也就只会用DDK开发驱动程序而已.
楼主的问题用我上面给出的代码还是可以解决的.我只是说个例子,未必就以定要用静态数组什么的.
char **
是字符指针的指针.不过在C++里面字符串等价字符指针,所以也可以说成是字符串的指针.
楼主的问题在Delphi不熟悉.不要用AllocMem给Delphi的动态数组分配内存.因为Delphi的动态数组有自己的管理方式.它也不是简单的数组,而是一个结构指针.和字符串类似而已.
没太多时间,别的我也不多说了.
 
还有补充一点,如果你一定要用AllocMem等给字符串,动态数组,变体变量,接口等类型的数组分配内存的话,Freemem前一定要Finalize.否则将会造成内存泄漏.因为FreeMem没有使他们的成员计数器减1.
 
顶部