与C语言对应的类型为char *,意为单字节字符串指针,在Delphi下的string类型是带引用计数的,有专门的内存管理sharemm单元,在dll之间引用该单元后可以导出使用string参数的导出函数,供delphi编译的exe使用(要注意delphi版本差异)
反之,delphi实现的功能要供其它语言调用时,字符串只能使用PAnsiChar或PChar,下面仅以PAnsiChar举例(PChar类同)
一、作用域问题
返回值或可变参数为PAnsiChar时,必须申请内存(通常是被调用方申请,调用方释放)
procedure GetString(Idx: Integer; var PStr: PAnsiChar);
var
temp: AnsiString;
begin
temp := 'hello world!';
if Idx = 0 then
begin
GetMem(PStr, Length(temp) + 1);// 多出这个1用来存\0字符串结束符
StrPCopy(PStr, temp);// 还有个StrPLCopy,可以带长度限制
end;
if Idx < 0 then
PStr := 'Not found';// 常量赋值无须申请内存和释放
if Idx > 0 then
PStr := PAnsiChar(temp);// 要注意了,作用域问题
end;
// 调用示例
var
P: PAnsiChar;
begin
GetString(0, P);//调用正常,P内容为'hello world!'
FreeMem(P);
GetString(-1, P);//调用正常,P内容为'Not found'
//FreeMem(P);//不可以释放,释放可能报错
GetString(1, P);//调用正常,P内容不确定,因为GetString过程中的temp可以已被回收
//FreeMem(P);//不可以释放,释放可能报错
end;
若以DLL形式提供API,遇到PAnsiChar返回值或可变参数时,最好不要使用栈上的string进行转换,在python中调用时无法获得正确的内容,推荐在堆上申请内存GetMem,告诉调用方要记得释放(挺麻烦,尽量用常量字符串吧)。
二、回调时强制转换栈上字符串变量为PAnsiChar可以得到正确结果,要注意目标语言环境(例如在python下调用可能就不行)
三、调用方释放内存,太麻烦了
看下Windows下的API是怎么实现的?
1、使用固定长度的字符串数组首地址当字符串指针,长度是固定的,不用申请释放了
2、先使用另一个API来测试返回字符串的长度,然后调用方申请内存,传指针地址,调用完成后调用方自己释放
3、使用常量字符串
4、尽量使用整形常量,减少字符串指针在API中的使用
5、其它待补充。。。