繰り返しますが、私は C に関する学生の質問に答えるクラスを教えています。これは、答えがわからないものsigned
です。unsigned
当然の選択だと思ったでしょう。それで、これは本当に設計上の決定でしたか?
5 に答える
標準に関しては(あなたの質問はそのようにタグ付けされているため) 、デフォルトとしてマークされました。これは、標準より前signed
のC実装の場合と同じであるためです。
元の ANSI/ISO 標準の義務は、新しい言語を作成するのではなく、既存の慣行を成文化することでした。したがって、論理的根拠のドキュメントに従って、標準化前の実装の動作が最も重要な要素でした。
元の X3J11 憲章は、共通の既存の慣行を成文化することを明確に義務付けており、C89 委員会は、それが明確で明確な場合は常に前例を堅持しました。
C89 で定義された言語の大部分は、Brian Kernighan と Dennis Ritchie による C プログラミング言語の初版の付録 A で定義されたものとまったく同じであり、当時のほとんどすべての C トランスレータで実装されていました。(以下、この文書をK&Rと呼びます。)
標準化前の実装が好まれた理由を知りたい場合はsigned
、UNIX と C が最初に開発された PDP-n マシンのアーキテクチャを調べなければならないでしょう。
History of Cページは、unsigned
実際には言語の比較的後発であり、70 年代半ばに登場したことを示しています。
1973 年から 1980 年にかけて、言語は少し成長しました。型構造は unsigned、long、union、および列挙型を獲得し、構造はほぼファーストクラスのオブジェクトになりました (リテラルの表記のみが欠けています)。
それは主に下位互換性と、符号付き整数と符号なし整数の両方を簡単にサポートできなかった初期の言語からの C の降下に関するものです。
C は、BCPL (CPL の簡易版) と呼ばれるさらに古い言語から派生した B と呼ばれる古い言語から派生しました。
BCPL はほとんど型付けされていない言語でした。変数宣言でオブジェクトの型が指定されていません。むしろ、特定の変数に対する操作は、それを特定の型であるかのように扱います。
BCPL 演算子+
、-
、*
、/
、およびは、オペランドを符号付き整数REM
として扱い、整数の結果を生成しました。
BCPL が符号なし整数をサポートしていた場合、別の演算子の符号なしオペランドのセットを持たなければならなかったか、負の数をまったく表現できなかったでしょう。(BCPL は浮動小数点をサポートしていないことに注意してください。)
B の構文は BCPL の構文とはかなり異なっていましたが (C に近いものでした)、同じセマンティクスの多くを保持していました。特に、変数と関数はデフォルトで整数型であり、unsigned
キーワードはありませんでした。
Bに基づく初期のCにもunsigned
キーワードはありませんでした。基本的な数値型は 、 、 、 の 4 つchar
だけint
でしfloat
たdouble
。( 、、unsigned
、 とともにが 1973 年から 1980 年の間に追加されました。) 言語の弱い型付けの性質を考えると、プログラマーは符号なし演算が必要なときにポインターを使用することがありました。long
union
enum
宣言された型のないエンティティが暗黙的に型であるという「機能」はint
、1999 年の ISO 標準が最終的に「暗黙のint
」規則を削除するまで、C で保持されていました。
さらに、符号付き整数型は、符号なし型よりも便利な傾向があります。負の値を表す機能は非常に便利です。典型的なラップアラウンド セマンティクスを考えると、2 つの小さな値の符号なし減算でエラーが発生すると、大きな正の値が生成される可能性があります (3 - 4 == 65535
たとえば、16 ビットの符号なし型の場合)。これらすべての言語の主なターゲットであるシステム プログラミング ドメインでさえ、負の値を表す必要がある場合があります (たとえば、ある量の変化)。
参考文献:
の既定の署名はchar
、言語によって定義されていません。これは実装によって定義されます。一部の CPU はより自然に符号付きの char であり、他の CPU はより自然に符号なしです。
unsigned
セマンティクスはより単純であることが保証されています: モジュロ基数 2 nで、例外はありません。ただし、 nが何であるかについて仮定しないでください。範囲のサイズは、対応する符号付き型のサイズと同じである必要はありません。
唯一の要件は、正の符号付きの値はすべて、対応する符号なしの型でも表すことができるということです。
の有効な実装の 1 つは、unsigned
2 の補数の符号付き算術演算を使用し、各演算の後に符号ビットをゼロにすることです。これは実際には起こりそうにありませんが、非 2 の補数演算を使用するマシンでは、負の数の論理をバイパスしようとするとさらに問題が発生する可能性があります。
実際には、負の数はどのハードウェア プラットフォームでも不可欠な機能ですが、レジスタ全体を正の数として扱う機能は、おまけです。C は、ハードウェアの最も効率的な部分を最も緊密にラップするように設計されています。