请原谅这个愚蠢的问题,但我很困惑。考虑以下方法(抱歉嘈杂的评论,这是一个正在开发的真实代码):
function HLanguages.GetISO639LangName(Index: Integer): string;
const
MaxIso639LangName = 9; { see msdn.microsoft.com/en-us/library/windows/desktop/dd373848 }
var
LCData: array[0..MaxIso639LangName-1] of Char;
Length: Integer;
begin
{ TODO : GetLocaleStr sucks, write proper implementation }
//Result := GetLocaleStr(LocaleID[Index], LOCALE_SISO639LANGNAME, '??');
Length := GetLocaleInfo(LocaleID[Index], LOCALE_SISO639LANGNAME, @LCData, System.Length(LCData));
Win32Check(Length <> 0);
SetString(Result, @LCData, Length); // "E2008 Incompatible types" here, but why?
end;
如果我删除了引用运算符,那么来自$X+
的隐式转换将进入救援并进行方法编译。为什么编译器拒绝使用引用运算符的代码是我无法理解的。
这是Delphi XE2,这种行为可能是特定的。
如果我在HLanguages.GetISO639LangName
范围内添加一个具有等效原型作为内在原型的测试用例,这个错误将会神奇地消失:
procedure SetString(var s: string; buffer: PChar; len: Integer);
begin
{ test case dummy }
end;
答案 0 :(得分:5)
您必须明确地将其转换为PChar
:
SetString(result,PChar(@LCData),Length);
正如你所说,SetString()
对第二个参数类型要求很高。它必须是PChar
PWideChar
或PAnsiChar
,具体取决于字符串类型本身。
我怀疑这是因为SetString()
被定义为重载了string
,WideString
或AnsiString
作为第一个参数。因此,为了验证正确的签名,它需要与所有参数类型完全匹配:
SetString(var s: string; buf: PChar; len: integer); overload;
SetString(var s: AnsiString; buf: PAnsiChar; len: integer); overload;
SetString(var s: WideString; buf: PWideChar; len: integer); overload;
当然,所有这些都是“内在函数”,所以你不会在system.pas中找到这样的定义,而是直接在_LStrFromPCharLen() _UStrFromPCharLen() _WStrFromPWCharLen()
之类的程序中找到这样的定义。
这种行为与Delphi的早期版本相同,并且不是XE2中的回归。
答案 1 :(得分:4)
我认为那里存在编译器错误,因为SetString
的行为与您提供的重载函数的行为不同。还有与Typed @运算符编译器选项的交互。我不知道你是怎么设置的。我总是启用它,但我怀疑我在那里是少数。
所以我无法解释奇怪的行为,并回答你提出的确切问题。我怀疑回答它的唯一方法是查看编译器的内部,我们中很少有人能做到这一点。
无论如何,如果有帮助,我认为传递参数的最简洁方法是这样的:
SetString(Result, LCData, Length);
无论你将Typed @ operator设置为。
,都会编译答案 2 :(得分:3)
我知道这并没有回答关于SetString的具体问题,但我想指出你可以通过简单的写作来做同样的事情
Result := LCData;
当分配给字符串时,Delphi将具有 ZERO 起始索引的char的静态数组视为具有最大长度的Null终止字符串。请考虑以下事项:
var
IndexOneArray : array [ 1 .. 9 ] of char;
IndexZeroArray : array [ 0 .. 8 ] of char;
S : string;
T : string;
begin
IndexOneArray := 'ABCD'#0'EFGH';
IndexZeroArray := 'ABCD'#0'EFGH';
S := IndexOneArray;
T := IndexZeroArray;
ShowMessage ( 'S has ' + inttostr(length(S)) + ' chars. '
+ #13'T has ' + inttostr(length(T)) + ' chars. ' );
end;
这显示一条消息,S有9个字符,而T有4个字符。 当零索引数组有9个非空字符时,它也会起作用。无论以下内存位置是什么,结果都将是9个字符。
答案 3 :(得分:0)
因为LCData
是指向array
的指针,而不是指向Char
的指针。当然,有时会发生数组或记录或类以char-type变量开头,但结果不是静态类型编译器应该依赖的结果。
您必须将指针指向该数组中的字符,而不是数组本身。
SetString(Result, @LCData[Low(LCData)], Length);