Plane int 64ビットを壊すことができますか?
-
14-10-2019 - |
質問
最近まで、私はほとんどのシステムの実装者/ベンダーが平凡にすることを決定したと考えました int
32ビット64ビットマシンでも、ある種の便利なwar贅。最新のC99固定サイズタイプで(int32_t
と uint32_t
, など)各サイズの標準整数タイプ8、16、32、および64がほとんど消えているように思えます。 int
64ビットにすることもできます。
しかし、平野のサイズの最大の結果 int
Cでは、Cが本質的により小さな算術を持っていないという事実から来ています。int
タイプ。特に、if int
32ビットより大きく、算術の結果 uint32_t
値にはタイプがあります signed int
, 、それはかなり不安です。
これが維持する正当な理由ですか int
実際の実装で32ビットで永続的に修正されましたか?はいと言うことに傾いています。の巨大なクラスの使用があるように思えます uint32_t
いつ壊れますか int
32ビットを超えています。単位のマイナスまたはビットワイズの補完オペレーターを適用することさえ、あなたがキャストしない限り危険になります uint32_t
.
もちろん、同じ問題が当てはまります uint16_t
と uint8_t
現在の実装については、誰もが知っているようで、それらを「より小さく」と扱うことに慣れているようです。int
" タイプ。
解決
あなたが言うように、私はプロモーションのルールが本当に殺人者だと思います。 uint32_t
その後、宣伝します int
そして、突然、ほとんどの人が署名していないことを期待する算術に署名したでしょう。
これは、あなたが算術だけを行い、に割り当てる場所にほとんど隠されています uint32_t
. 。しかし、定数と比較する場所では致命的である可能性があります。明示的なキャストを行わずにそのような比較に依存しているコードが合理的であるかどうかはわかりません。のようなキャスト定数 (uint32_t)1
非常に退屈になる可能性があります。私は個人的には少なくとも常に接尾辞を使用しています U
私が署名しないようにしたい定数の場合、しかしこれはすでに私が望むほど読むことができません。
また、それを念頭に置いてください uint32_t
などは存在することが保証されていません。さえありません uint8_t
. 。その施行は、POSIXからの拡張です。したがって、その意味で、言語としてのCは、その動きをすることができません。
他のヒント
「リーズナブルなコード」...
まあ...開発についてのことは、あなたはそれを書いて修正してから、それが機能することです...そしてあなたは停止します!
そして多分あなたはたくさん燃やされたので、あなたは特定の機能の安全な範囲内に留まります、そして、あなたは火傷していないかもしれません その特定の方法 ですから、あなたはあなたが変化する可能性のある何かに頼っていることに気づきません。
または、あなたがバグに依存していることです。
Olden Mac 68000コンパイラでは、Intは16ビット、Longは32でした。しかし、それでもほとんどの現存するCコードはINTが32であると想定していたため、ニュースグループで見つけた典型的なコードは機能しません。 (ああ、そしてMacはprintfを持っていませんでしたが、私は脱線します。)
だから、私が得ているのは、はい、あなたが変わったら なんでも, 、その後、いくつかのことが壊れます。
最新のC99固定サイズタイプ(INT32_TおよびUINT32_Tなど)では、各サイズの標準整数タイプ8、16、32、および64がほとんど消えます。
C99には、固定サイズのタイプではなく、固定サイズのtypedefsがあります。ネイティブC整数タイプはまだです char
, short
, int
, long
, 、 と long long
. 。それらはまだ関連しています。
ILP64の問題は、CタイプとC99 Typedefsの間に大きな不一致があることです。
- int8_t = char
- int16_t = short
- int32_t = 標準以外のタイプ
- int64_t = int、long、またはlong long
残念ながら、ILP64モデルは、32ビットデータ型を記述する自然な方法を提供しておらず、駐車不可能な構成要素に頼らなければなりません。
__int32
そのようなタイプを説明します。これは、32ビットと64ビットの両方のプラットフォームで実行できるコードを作成する際に実際的な問題を引き起こす可能性があります#ifdef
構造。タイピング情報がアプリケーションによって外部的に表示されなかった場合でも、データセットへの投資を維持しながら、そのような変更を行う必要なく、大量のコードをLP64モデルにポートすることができました。
Dec AlphaとOSF/1 UNIXは、UNIXの最初の64ビットバージョンの1つであり、64ビット整数 - ILP64アーキテクチャ(意味 int
, long
ポインターはすべて64ビットの量でした)。それは多くの問題を引き起こしました。
私が見たことのない問題の1つ - それが私が長い間答えている理由です - あなたが64ビットを持っているなら int
, 、どのサイズを使用していますか short
? 16ビット(クラシック、変更なしアプローチ)と32ビット(ラジカル 'ウェル、 short
半分の長さでなければなりません int
'アプローチ)はいくつかの問題を提示します。
C99で <stdint.h>
と <inttypes.h>
ヘッダーは、36ビットまたは60ビットの整数を持つマシンを無視することを選択した場合、固定サイズの整数からコーディングできます(少なくとも準単位)。ただし、ほとんどのコードはこれらのタイプを使用して記述されておらず、通常、モデルが既存のバリエーションから出発した場合に動揺するコードに、根深く、主に隠された(しかし根本的に欠陥のある)仮定があります。
64ビットウィンドウのMicrosoftの超保守的なLLP64モデルに注意してください。 32ビットモデルが変更された場合、あまりにも古いコードが破損するため、これは選択されました。ただし、ILP64またはLP64アーキテクチャに移植されたコードは、違いのためにLLP64にすぐに移植できませんでした。陰謀理論家は、64ビットUnixが64ビットウィンドウに移植されることをより困難にすることを意図的に選択したと思われるでしょう。実際には、それが幸せな(マイクロソフトにとって)副作用以上のものであるかどうかは疑問です。 32ビットのWindowsコードは、LP64モデルを使用するために多くの改訂を修正する必要がありました。
INTが64ビットである場合に壊れるコードイディオムが1つあります。
- ifをテストすることにより、値が負のかどうかを確認します
((val & 0x80000000) != 0)
これは、エラーコードのチェックでよく見られます。多くのエラーコード標準(ウィンドウなど HRESULT
)ビット31を使用してエラーを表します。また、コードは、ビット31をテストするか、エラーが負の数であるかどうかを確認することにより、そのエラーを確認することがあります。
HRESULTをテストするためのMicrosoftのマクロは両方の方法を使用します - そして、SDKマクロを使用せずに同様のコードがたくさんあると確信しています。 MSがILP64に移動した場合、これはLLP64モデル(またはLP64モデル)で完全に回避される頭痛の移植を引き起こす1つの領域になります。
注:「ILP64」などの用語に慣れていない場合は、回答の最後にあるミニ光沢のあるものをご覧ください。
これらのINTのサイズが32ビットであると仮定して、プレーンオールドインントを使用してエラーコードを保持するコード(必ずしもWindows指向ではない)がたくさんあると確信しています。また、両方の種類のチェックも使用するエラーステータススキームを備えたコードがたくさんあるに違いありません(< 0
また、ビット31が設定されています)。これらのチェックは、エラーコードが慎重に構築されてサインエクステンションが行われるように慎重に構築された場合、どちらの方法でも正しく機能し続けることができますが、繰り返しますが、私が見た多くのシステムは、ビットフィールドを組み合わせることでエラー値を構築します。 。
とにかく、これは決して解決できない問題ではないと思いますが、ILP64プラットフォームに移動した場合、多くのコードが修正を必要とするかなり一般的なコーディングプラクティスだと思います。
また、これがMicrosoftがLLP64モデルを選択するための最も重要な理由の1つであるとは思わないことに注意してください(その決定は、32ビットと64ビットのプロセスの間のバイナリデータの互換性によって大きく促進されたと思います。 MSDNで言及されています と レイモンドチェンのブログで).
ミニ光沢 64ビットプラットフォームプログラミングモデルの用語の場合:
- ILP64:
int
,long
, 、ポインターは64ビットです - LP64:
long
ポインターは64ビットです。int
32ビット(多くの(ほとんど?)UNIXプラットフォームで使用されています) - LLP64:
long long
ポインターは64ビットです。int
とlong
32ビットのまま(Win64で使用)
64ビットプログラミングモデルの詳細については、参照してください 「64ビットプログラミングモデル:なぜLP64?」
私は個人的にこのようなコードを書いていませんが、私はそれが複数の場所でそこにあることに違います...そしてもちろん、あなたがのサイズを変更するとそれは壊れます int
.
int i, x = getInput();
for (i = 0; i < 32; i++)
{
if (x & (1 << i))
{
//Do something
}
}
まあ、それはこの話がすべて新しいようではありません。 「ほとんどのコンピューター」では、デスクトップコンピューターを意味すると思います。すでに16ビットから32ビットへの移行がありました int
. 。今回は同じ進行が起こらないと言うことはありますか?
特にそうではありません。 INTは、約64ビットアーキテクチャ(x64ではなく)で64ビットです。
標準では、実際には32ビットの整数を獲得することは保証されていません。
これで、intに依存している場合、ptrdiff_tと同じサイズが壊れている可能性があります。
Cは、マシンがバイナリマシンであることさえ保証しないことを忘れないでください。