开放字符串(openstring)参数使用总结
pascal吧
全部回复
仅看楼主
level 1
黄金止手 楼主
此参数一般来说用不上。
而且 FP 档案里似乎也没写过这种参数的用法,Delphi 官网上也似乎找不到。这里我试图自己总结一下。
此类型和开放数组一样,只能出现于参数列表中,不是真实的类型。
用法:在参数列表中声明类型为 openstring 。可以带 var/out/const/constref 修饰。不带修饰时为按值传递,带修饰时为按引用传递。
限制:只能给 openstring 参数传入短字符串。
按值传递时,其他类型如 PChar 和 AnsiString 会被转换短字符串,并在长度 255 处截断。按引用传递时,传入参数必须是短字符串,const/constref 允许传入字符串字面常量,此时字面常量会在内存中作为短字符串实例化。
openstring 参数会在栈上传字符串本身的地址(同下标 0 元素的地址)和字符串最大长度,最大长度即声明 string[N] 中的 N (对于 ShortString 和默认的 string 此值为 255),会由编译器记录并传递。
按值传递时,子程序会在栈上把字符串复制一遍,再使用复制后的字符串地址,此行为同开放数组。
2016年09月11日 15点09分 1
level 1
黄金止手 楼主
关于短字符串:
默认模式下,在 FPC 中声明的 string 即为最大长度 255 的单字节字符串。
在其他平台(如 Delphi,或使用 {$H+} 的 FPC)上 string 可能是别的类型。这时可以用 ShortString 这个名字表示我们习惯的最大长度 255 的单字节字符串。
要声明更短的短字符串,可以用 string[N] ,N 取值范围为 1..255 。
短字符串下标取值范围为 0..N (N 为声明最大长度,对于普通 string/ShortString 为 255),字符串当前长度在下标 0 处记录,首字符下标为 1 。
短字符串类似静态数组(但与数组属于不同类型),为值类型,赋值时会直接复制整个字符串。
与之相对, FP 中其他字符串都是动态的引用类型,类似动态数组,赋值时只会增加引用数。其他字符串在声明处相当于一个指针,指向实际字符串内容的首个字符。
短字符串作为参数传递时的问题:
在传递参数时,所有长度的短字符串都能传递给 string 类型。(这里假设 string 就是 string[255],或者说 ShortString)
这在作为值或常量传递时没问题,但传递给 var/out 参数时就可能产生访问越界。
譬如倘若声明了
SStrArr:array[0..3] of string[7];
将 SStrArr[0] 传给 var sstr:string 参数后,在方法中修改 sstr[8] 不会发生运行时错误。但这会修改了 SStrArr[1] 的首字节,导致了访问越界的逻辑错误。
2016年09月11日 15点09分 3
level 1
黄金止手 楼主
openstring 引入的动机:
openstring 是用来处理最大长度不同的短字符串的。
将短字符串传入 openstring 参数后,对参数用 high() 的返回值即是声明的字符串最大长度,能提供一种避免产生越界问题的手段。
目前 FPC 中 const openstring 参数传入字符串字面常量时,high() 取得的最大长度结果有误(比实际值小 1 )。可能是因为字符串字面常量在 FPC 中有两种实例化方式的缘故(一种是字符数组,一种是短字符串)。不过因为参数是 const ,故可认为问题不大。
openstring 的限制:
只能处理短字符串。
按值传递时,传入的 PChar 和 AnsiString 等类型都要被转化成最大长度为 255 的短字符串。
按引用传递时,只能接受短字符串参数。
FPC 3.0.0 中 const/constref 修饰的 openstring 参数在编译时可以接受 AnsiString ,但此时运行结果必然错误。可能以后会修改成编译错误。
[滑稽]另外 Win32 平台下的 FPC 3.0.0 中,试图给按引用传递的 openstring 参数传指针会导致编译器本身崩溃。
2016年09月11日 15点09分 4
level 1
黄金止手 楼主
openstring 的不必要性:
一般来说内存不紧张的时候,短字符串可以全部声明成 string 。
这样即使用 var sstr:string 也不会导致越界。
而且还有不少场合是可以按值传递或使用 const 参数的,也不会出问题。
另一方面,需要使用它的场合——一个子程序要修改最大长度不同的字符串——其实不算多见。
实用中,不同最大长度的短字符串一般不会用来记录同类的名称,不必用同一子程序来修改。
附:关于 string 的可变性:
FPC 中默认模式下 string 等于 ShortString ,即 string[255] 。
但在 {$H+} 打开或 {$mode Delphi} 模式下,string 会成为 AnsiString 的别名。此时仍可用带最大长度的方式和 ShortString 类型声明短字符串。
Delphi 2009 版本之前,string 默认是 AnsiString 的别名。
从 Delphi 2009 开始,string 默认是 UnicodeString 的别名,同时 Delphi 中 Char 也变成了双字节 WideChar 的别名,单字节字符的名称改用 AnsiChar 。
2016年09月11日 16点09分 5
level 1
黄金止手 楼主
补充……
当编译开关 $V 或 $VARSTRINGCHECKS 打开时,不同长度的短字符串将会视作不同类型,按引用传递时互不兼容。
当编译开关 $P 或 $OPENSTRINGS 打开时,参数列表中的 string 可以自动作为 openstring 处理。
2016年09月11日 17点09分 6
1