他のいくつかの言語と比較したCの興味深い特徴は、そのデータ型の多くが、絶対条件で指定されるのではなく、ターゲットアーキテクチャのワードサイズに基づいていることです。これにより、特定のタイプでは困難なマシンでコードを記述するために言語を使用できますが、異なるアーキテクチャで一貫して実行されるコードを設計することは非常に難しくなります。コードを考慮してください:
uint16_t ffff16 = 0xFFFF;
int64_t who_knows = ffff16 * ffff16;
int
16ビットのアーキテクチャでは(多くの小さなマイクロコントローラーに当てはまります)、このコードは明確に定義された動作を使用して値1を割り当てます。int
64ビットのマシンでは、明確に定義された動作を使用して、値4294836225を割り当てます。int
32ビットのマシンでは、-131071の値を割り当てる可能性があります(それが実装定義の動作か未定義の動作かはわかりません)。コードは名目上「固定サイズ」タイプであると想定されるもの以外は何も使用しませんが、標準では、現在使用されている2種類のコンパイラーが2つの異なる結果を生成し、今日の多くの一般的なコンパイラーが3番目を生成する必要があります。
この特定の例は、実際のコードでは2つの16ビット値の積を直接64ビット値に割り当てるとは思わないという点で、多少不自然ですが、3つの方法の整数を示す簡単な例として選ばれました。プロモーションは、固定サイズと思われるサイズの符号なしタイプと対話する場合があります。符号なしの型の数学を数学的な整数演算のルールに従って実行する必要がある現実の状況、モジュラー演算のルールに従って実行する必要のある状況、実際にそうでない状況があります問題ない。チェックサムなどの実世界のコードの多くは、算術に依存しており、少なくとも、未定義の動作をトリガーするのではなく、正確なmod 65536として定義されている結果を取得します。uint32_t
算術ラッピングmod2³²におり、任意のを実行できます。uint16_t
この状況は明らかに望ましくないと思われますが(多くの目的で64ビット処理が標準になると、より多くなります)、私が観察したC標準委員会は、いくつかの顕著な生産ですでに使用されている言語機能を導入することを好みます環境を「ゼロから」作成するのではなく、C言語には、型を格納する方法だけでなく、可能なプロモーションを含むシナリオでの型の動作をコードで指定できる顕著な拡張機能がありますか?コンパイラー拡張機能がそのような問題を解決する可能性がある少なくとも3つの方法を見ることができます。
特定の「基本的な」整数型を特定のサイズに強制するようにコンパイラーに指示するディレクティブを追加します。
ターゲットアーキテクチャ上の型の実際のサイズに関係なく、マシンの型が特定のサイズを持っているかのように、さまざまなプロモーションシナリオを評価するようコンパイラーに指示するディレクティブを追加します。
添加;(特定の特性を有するタイプに関係なく、基礎となるワードサイズの、MOD-65536ラッピング代数環として振る舞うべきであり、他のタイプに暗黙的に変換すべきではないこと、例えば宣言をタイプを宣言する手段を可能にすることによって
wrap32
には、int
得られるはずが16ビットより大きいwrap32
かどうかに関係なく、型の結果。ただしint
、にwrap32
直接aを追加するwrap16
ことは不正です(どちらも他方に変換できないため)。
私自身の好みは3番目の選択肢です。なぜなら、異常なワードサイズのマシンでさえ、変数が2のべき乗サイズの場合と同じように「ラップ」する多くのコードで動作できるからです。コンパイラは、型を適切に動作させるためにビットマスキング命令を追加する必要がありますが、コードがmod 65536をラップする型を必要とする場合、ソースコードを乱雑にするよりも、それを必要とするマシンでコンパイラにそのようなマスキングを生成させる方が良いですまたは、そのようなマスキングが必要なマシンで使用できないため、単純にそのようなコードを持っています。しかし、上記の手段のいずれかを介して、または私が考えていない手段を介してポータブルな動作を実現する一般的な拡張機能があるかどうか、私は興味があります。
私が探しているものを明確にするために、いくつかのことがあります。最も顕著な:
望ましいセマンティクスを確保するためにコードを記述する方法は多数ありますが(たとえば、特定のサイズの符号なしオペランドで数学を実行して、明示的にラップするかしないかの結果を得るために実行するマクロを定義する)、または少なくとも望ましくないセマンティクス(たとえば、a が昇格しないコンパイラーで条件付きで型
wrap32_t
を定義し、その型が昇格するマシンでコンパイルに失敗する必要があるコードの方が、実行して偽の動作をもたらすよりも優れていると考える)将来の言語拡張機能で最も有利に動作するコードを記述する方法がある場合、それを使用することは、独自のアプローチを考案するよりも優れているでしょう。uint32_t
uint32_t
wrap32_t
多くの整数サイズの問題を解決するために言語をどのように拡張できるかについて、かなり堅実なアイデアがあり、コードが異なるワードサイズのマシンで同一のセマンティクスをもたらすことを可能にしますが、それらを書くのにかなりの時間を費やす前にその方向でどのような努力が既に行われたかを知るため。
私は、C標準委員会または彼らが作成した作業を軽disするような見方を決して望みません。ただし、「自然な」プロモーションタイプが32ビットであるマシンと64ビットであるマシンで、数年以内にコードを正しく動作させることが必要になると思います。言語の控えめな拡張(C99 nnd C14間の他の多くの変更よりも控えめ)を使用すると、64ビットアーキテクチャを効率的に使用するクリーンな方法を提供できるだけでなく、バーゲンでも標準が歴史的に後方に曲げてサポートするために「異常なワードサイズ」のマシン(例えば、12ビットのマシンを可能にするchar
、uint32_t
mod2³²をラップする]。将来の拡張機能の方向に応じて、デフォルトの整数型が「期待される」ように動作する今日のコンパイラで使用できるマクロを定義できるようになると期待していますが、整数の将来のコンパイラでも使用できますタイプのデフォルトの動作は異なりますが、必要な動作を提供できる場所です。
int
がより大きい場合uint16_t
、乗算のオペランドは昇格さint
れ、乗算はint
乗算として実行され、結果のint
値はint64_t
の初期化のために変換されますwho_knows
。