4

ばかげた質問で申し訳ありませんが、私は混乱しています。次の方法を検討してください (ノイズの多いコメントで申し訳ありません。これは開発中の実際のコードです)。

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 であり、この動作は Delphi XE2 に固有のものである可能性があります。


そして、このエラーの範囲内で、同等のプロトタイプを組み込みのテスト ケース ダミーとして追加すると、HLanguages.GetISO639LangName魔法のように消えます。

procedure SetString(var s: string; buffer: PChar; len: Integer);
begin
  { test case dummy }
end;
4

4 に答える 4

5

明示的に次のように変換する必要がありますPChar

SetString(result,PChar(@LCData),Length); 

あなたが言ったようにSetString()、2番目のパラメータタイプについては非常に厳しいです。文字列型自体に応じて、PCharどちらか一方のPWideCharいずれかである必要があります。PAnsiChar

これは、、、、または1番目のパラメーターのSetString()いずれかでオーバーロードされたものとして定義されているためだと思います。したがって、正しい署名を検証するには、すべてのパラメータタイプが完全に一致している必要があります。stringWideStringAnsiString

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のリグレッションではありません。

于 2012-11-28T21:33:12.563 に答える
4

SetStringの動作は、提供するオーバーロードされた関数の動作とは異なるため、コンパイラのバグがあると思います。さらに、Typed@演算子コンパイラオプションとの相互作用があります。どうやって設定したのかわかりません。私はいつもそれを有効にしますが、私はそこの少数派にいるのではないかと思います。

だから私は奇妙な行動を説明することはできず、あなたが尋ねる正確な質問に答えることはできません。それに答える唯一の方法はコンパイラの内部を見ることだと思いますが、それができる人はほとんどいません。

とにかく、それが役立つ場合は、パラメータを渡す最もクリーンな方法は次のようになります。

SetString(Result, LCData, Length); 

これは、Typed@演算子を何に設定してもコンパイルされます。

于 2012-11-28T22:28:11.273 に答える
3

これが SetString に関する特定の質問に答えていないことはわかっていますが、単に書くだけで同じことができることを指摘したいと思います

Result := LCData;

文字列に代入する場合、 Delphiは開始インデックスが 0 の 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 個の非 null 文字がある場合にも機能します。結果は、次のメモリ位置に関係なく 9 文字になります。

于 2012-11-29T13:48:43.337 に答える
0

LCDataは へのポインタであり、 へのポインタではarrayないためですChar。確かに、配列、レコード、またはクラスが char 型の変数で始まることがありますが、その結果は、静的に型指定されたコンパイラが依存するものではありません。

配列自体ではなく、その配列内の文字へのポインターを取得する必要があります。

SetString(Result, @LCData[Low(LCData)], Length); 
于 2016-04-14T09:52:14.570 に答える