18

私は Pascal の初心者ではありませんが、DelphiFree Pascalが通常、パラメーターと戻り値を符号付き整数として宣言するのに、常に正でなければならない理由はまだわかりません。例えば:

  • Pos()整数型を返します。マイナスになる可能性はありますか?
  • SetLength()NewLengthパラメータを整数型として宣言します。文字列に負の長さはありますか?
  • System.THandle倍長整数として宣言されています。ハンドルに負の数はありますか?

Delphi や Free Pascal のような決定がたくさんあります。その背後にはどのような考慮事項がありましたか?

4

4 に答える 4

18

Pascal では、整数 (符号付き) が基本型です。他のすべての整数型は整数の部分範囲です。(TP では longint が、Delphi では int64 が与えられているため、Borland 方言ではこれが完全に当てはまるわけではありませんが、十分に近いです)。

その重要な理由は、計算の中間結果が負になり、符号なし整数で計算すると、範囲チェック エラーがトリガーされ、ほとんどの古いプログラミング言語は 2 の補数の整数を想定していないため、結果 (範囲チェックがオフの場合)破損している可能性さえあります。

THandle のケースはもっと単純です。Delphi には、D4 まで適切な 32 ビット符号なしはありませんでしたが、31 ビット カーディナルしかありませんでした。(32 ビットの符号なし整数は整数の部分範囲ではないため、後の符号なし整数は int64 のサブセットであり、D2010 でのみ追加された uint64 に問題が移動しました)

そのため、ヘッダーの多くの場所で、winapi が署名されていない型を使用する場所で、署名された型が使用されます。おそらく、これらのバージョンで 32 番目のビットが誤って破損し、カスタムが動かなくなるのを防ぐためです。

しかし、winapi のケースは一般的なケースとは異なります。

後で追加された一部の Pascal (および Modula2/3) 実装では、整数を wordsize よりも大きいサイズに設定することでこのトラップを回避し、以下のプログラムのように、すべての数値型に適切な部分範囲を宣言するよう要求します。

1つ目は、すべてが整数のサブセットであるという主な仮定を保持し、2つ目は、特にCPUにワード操作よりも大きな操作がある場合に、コンパイラがレジスタに収まるようにほぼすべてを縮小できるようにします。(32 ビット * 32 ビット mul で 64 ビットの結果が得られる x86 のように、ステータス ビットを使用してワードサイズのオーバーフローを検出できます (たとえば、完全な 2*ワードサイズの加算を行わずに加算の範囲例外を生成するため))

   var x : 0..20;
       y : -10..10;
       
   begin
     // any expression of x and y has a range -10..20

Turbo Pascal と Delphi は、16 ビットおよび 32 ビット製品のワードサイズの 2 倍の整数型をエミュレートします。最上位の u​​nsigned 型の処理はせいぜいハックです。

于 2012-10-08T12:43:59.017 に答える
13

まあ、最初THandleは間違って宣言されています。Windows ヘッダーでは署名されていませんが、Delphi では署名されていないはずです。実際、これは Delphi の最近のリリースで修正されたと思います。

署名されていないものよりも署名されているものの好みは、主に歴史的なものであり、特に重要ではないと思います。ただし、それが重要な例を 1 つ思いつくことができます。for ループを考えてみましょう:

for i := 0 to Count-1 do

iが符号なしで0 の場合Count、このループは 0 から実行されますが、$FFFFFFFFこれは望ましくありません。符号付き整数ループ変数を使用すると、この問題を回避できます。

ここで、Pascal はその構文の被害者です。同等の C または C++ ループにはそのような問題はありません

for (unsigned int i=0; i<Count; i++)

構文の違いと、比較演算子を停止条件として使用しているためです。

Length()これは、文字列または動的配列で符号付きの値が返される理由でもあります。したがって、一貫性のために、SetLength()符号付きの値を受け入れる必要があります。また、 の戻り値がPos()文字列のインデックスに使用されることを考えると、これも署名する必要があります。

このトピックに関する別のスタック オーバーフロー ディスカッションを次に示します。メンバーのカウントに符号なし整数を使用する必要がありますか?

もちろん、ここでは勝手に推測しています。おそらく、設計がなく、習慣から、符号付きの値を使用する前例が設定され、安置されました。

于 2012-10-08T12:20:24.667 に答える
6

符号付き整数を使用する理由は多数ありますが、負の値を返すつもりがない場合に当てはまる場合もあります。

Pos を呼び出すコードを書き、その結果を計算したいとします。負の結果(Pos('x',s)-5)で範囲チェック例外を発生させ、アンダーフローして 40 億前後の非常に大きな符号なしの数値になるか、または負になるかをPos('x',s)返します1。どちらも、これらのケースについてめったに考えない新しいユーザーにとっては問題の原因となりますが、結果を使用することによって、負の結果とゼロの結果をチェックし、それらを文字列オフセットとして使用しないようにするのは、長い間確立された伝統です。Integer初心者および上級プログラマーにとって、Integer を使用する利点があり、「負の」値が下に転がって大きな符号なしの値になったり、範囲例外を発生させたりすることはありません。

第 2 に、プログラミングの開始時には、通常、Integer(符号付き) 型を導入する前に、Cardinal. 初心者は のような関数を扱うことが多くPos、副作用の最も不親切なセットを作成する型を使用することは理にかなっています。絶対に必要な範囲よりも大きな範囲を設定しても、悪影響はありません (おそらく Pos に必要な範囲は、1 から Delphi の最大文字列長までです)。32 ビットの DelphiCardinalでは、Pos に型を使用する利点はまったくなく、それを選択することには間違いなく欠点があります。

ただし、64 ビットの Delphi に到達すると、理論的には Integer が保持できるよりも大きな文字列を持つ可能性があり、Cardinal に移行しても潜在的な問題がすべて解決されるわけではありません。ただし、2 GB 以上の文字列を持つ可能性はおそらくゼロであり、Delphi 64 ビット コンパイラは>2 GB文字列を許可しません。私のテストでは、64 ビット Delphi でほぼ 1 GB の文字列を達成できました。したがって、Win64 文字列の実質的な長さの制限は約 10 億 (1073741814) 文字であり、実際の RAM を 2 GB 近く使用しています。その制限では、EIntOverflowまたはEAccessViolationのいずれかを取得します。適切に定義された制限ではなく、Delphi ランタイム ライブラリ (RTL) のバグに遭遇しているように見えるため、マイレージは異なる場合があります。

于 2012-10-08T18:29:19.723 に答える
6
于 2012-10-08T12:21:47.560 に答える