c99で長く長い
C99標準では、彼らはを導入しましたlong long
。これの目的は何ですか?私の(限られた)Cプログラミングの経験では、4バイトのintと8バイトの長さしか見たことがありません。たとえば、コンパイラエクスプローラから:
場合はlong
、すでにある8
そして、なぜそれが別追加する必要があるlong long
タイプ?これはコンパイラ/アーキテクチャに何をしますか?
回答
longがすでに8である場合、なぜ別のlong long型を追加する必要があるのですか?これはコンパイラ/アーキテクチャに何をしますか?
「longがすでに8の場合」は、32ビットlong
およびint
32ビットまたは16ビットに依存するコードが存在するため、常に当てはまるとは限りません。
long
64ビットとして要求すると、コードベースが破損します。これは大きな懸念事項です。
ただし、long
32ビットのままにする必要がある(およびしないlong long
)必要がある場合は、標準の64ビット整数にアクセスできませんlong long
。したがって、の論理的根拠があります。
可能long
32ビットまたは64ビット(または他のもの)のいずれかが遷移を可能にするように。
さまざまな関数がのlong
ように受け渡し/返しfseek(), ftell()
ます。long
大きなファイルをサポートするために32ビット以上であるという利点があります。
推奨される方法は、より広い範囲を推奨します。「実装がこれを必要とするのに十分な大きさのオブジェクトをサポートしない限り、long
使用される型size_t
とptrdiff_t
それよりも大きい整数変換ランクを持つべきではありませんsigned long int
。」これは、32ビットを超えるメモリサイズに関連しています。
おそらく将来的には、実装はint/long/long long/intmax_t
32/64/128/256ビットとして使用される可能性があります。
IAC、固定幅タイプのintN_t
人気がlong
とよりも高まっているのがわかりlong long
ます。私は固定幅のタイプを使用する傾向があるかbool
、( )、unsigned
/ 、、( )及び休暇(、 )(、) (、 )特別な場合のために。char
int
unsigned
size_t
u
intmax_t
signed char
unsigned
short
unsigned
long
unsigned
long long
C標準はint
、along
が(大まかに言えば)2バイト、aが4バイト、along long
が8バイトであることを保証するだけです。
実際、MSVClong
は4バイトint
ですが、それでも4バイトを使用します。
int
andlong
に関連する唯一の要件は、当時と現在、int
少なくとも16ビットでlong
あり、少なくとも32ビットである必要があるということです。16ビットシステムと32ビットシステムはどちらも32ビットlong
である傾向があり、64ビットマシンは1990年代後半にはあまり一般的ではありませんでした。そのため、C99より前は、プログラマーは64ビット整数型を利用できることに移植的に依存することはできませんでした。この問題はlong long
、少なくとも64ビットである必要があるの導入によって解決されました。(私はそれがGCCと多分他のコンパイラによって拡張としてすでに提供されたと信じています)。
最近では、多くの(すべてではありませんが)64ビットシステムが64ビットを使用し、それ以上大きくlong
する必要がないlong long
ため、64ビットでもあり、ある意味で冗長です。それらはおそらくあなたが精通しているシステムですが、そこにあるすべてを表すわけではありません。
私はあなたがCタイプ幅要件がどのように機能するかについての巨大な間違った仮定を作っていることを認識していなかったと思う:ISO Cは、ちょうど最小値、範囲設定許可されている最小の-大きさのようなLONG_MAX
とLONG_MIN
(-2147483647、ありません8をISO C理由2の補数だけでなく、1の補数と符号/大きさの符号付き整数を許可します。)実際の実装では、より広い型を使用できます。多くの場合、ターゲットマシンが効率的に実行できるレジスタ幅またはオペランドサイズに一致します。
これについては、Stack Overflowやその他の場所で多くのことが書かれていますが、ここでは繰り返しません。も参照してくださいhttps://en.cppreference.com/w/c/language/arithmetic_types
そのため、x86-64 System V ABIのタイプ幅の選択を見て、他のC実装が同じであると想定するという間違いにつながったと思います。x86-64は、64ビット整数を効率的に処理できる64ビットISAであるため、64ビットlong
はかなり適切な選択でした。
i386のような32ビットマシンの正常なABIは、64ビットを使用するlong
必要はなく、32ビットのみを使用するためです。64ビットを使用すると、単一のレジスタに収まらないことを意味します。でコンパイルする-m32
か、32ビットARM用にコンパイルします。GodboltにはAVRとMSP430用のGCCもあります。これらの8ビットおよび16ビットマシンでは、GCCはISO Cで許可されている最小の幅(2バイトint
など)を選択します。
1999年には、x86-64は存在しませんでした。(Alphaのように、他のいくつかの64ビットISAが実行しました)。したがって、2つの主流のABIの1つを見て、C99の選択を理解することは、それほど遠くまでは行きません。
もちろん、Cは、64ビット整数演算を効率的に実行するプログラムを作成できるようにするために、少なくとも64ビットであることが保証されている型を必要とします。
そしてところで、x86-64は32ビット整数を64ビットと同じくらい効率的に、時にはもっと効率的に行うことができます。したがってlong
、64ビット型を作成することは間違いなく素晴らしいことではありません。一部のコードはlong
、32ビットである必要がある型が必要なために使用しますが、幅を広くしてもメリットはありません。このようなコードの場合、64ビットはlong
キャッシュフットプリント/メモリ帯域幅、およびコードサイズ(REXプレフィックス)を浪費するだけです。C99では理想的な選択ですがint_least32_t
、入力するのに煩わしく長く、ほとんど使用されません。
しかし、OTOHは、long
「最も広く効率的な(1レジスタ)タイプ」であることが期待される場合がありますが、そのような保証long
はなく、32ビットのWindowsx64のようなLLP64ABIはそのようなものではありません。
ワームのもう1つの可能性は、C99int_fast32_t
およびx86-64 System VのIMOで、64ビットタイプにするのに適していません。(私はハーフ答弁書を持っている理由は、それがuint64_tを?に解決んuint64_tをに解決さuint32_fast_t CPPが、のuint32_t(x86_64版)。よりも、ほぼすべての操作のために遅いです...私は終える必要がありますint_fast32_t
何のために速い」という問題を提起します目的」であり、多くの実装では、多くの場合に期待するものではありません。
も参照してください
- C ++-最速の整数型?
- [u] int_fastN_tタイプは、x32 ABIの有無にかかわらず、x86_64に対してどのように定義する必要がありますか?
- uint_fast32_tよりもuint32_tが優先されるのはなぜですか?
- x86_64での乗算でuint_least16_tがuint_fast16_tよりも速いのはなぜですか?
- 「int」、「least」、および「fast」の非固定幅タイプC / C ++を介して許可されるコンパイラーの最適化
いくつかの制限がありますが、コンパイラーの作成者は、標準のC変数タイプ(char、short、int、long、long long)の長さを自由に選択できます。当然、charはそのアーキテクチャのバイトになります(Cコンパイラのほとんどは8ビットです)。そして当然、小さいものを大きいものより大きくすることはできません。長いものをintより小さくすることはできません。しかし確かに1999年までに、x86の16ビットから32ビットへの移行が見られました。たとえば、intは多くのツールで16から32に変更されましたが、長い間32のままでした。その後、32ビットから64ビットへのx86移行が発生し、ツールによっては使用可能なタイプがありました。助けるために。
問題はこれよりずっと前に存在し、解決策は型の長さを修正することではありませんでした。ルールの範囲内で、サイズに関してはコンパイラの作成者次第です。ただし、コンパイラの作成者は、ツールとターゲットに一致するstdint.hファイルを作成する必要があります(stdint.hは、少なくともツールとターゲットに固有であり、ツールのバージョンであり、そのツールのオプションをビルドすることもできます)。たとえば、uint32_tは常に32ビットです。一部の作成者は、stdint.hでそれをintに変換します。C言語の変数タイプは、言語ごとにchar、short、intなどに制限されたままです(uint32_tは変数タイプではなく、stdint.hを介して変数タイプに変換されます)。この解決策/回避策は、すべてが狂わないようにし、言語を存続させる方法でした。
作成者は、たとえば、GPRが16ビットである場合はintを16ビットにする場合、32ビットを32ビットにする場合などを選択することがよくありますが、ある程度の自由度があります。
はい、これは特に、特定のターゲット(たとえば、これを読んでいるコンピューター)の2つのツールがintとlongに同じ定義を使用していると想定する理由がないことを意味します。また、次のコードを記述したい場合はこれらのツール間で移植できるこのプラットフォーム(このプラットフォームをサポートする)は、int、longなどではなくstdint.hタイプを使用します...プラットフォームを横断する場合は、msp430 mcu、arm mcu、armlinuxマシンです。 、x86ベースのマシンで、同じ「ツールチェーン」(たとえば、gnu gccとbinutils)の場合でも、intとlongなどの定義が同じではありません。charとshortは8ビットと16ビットになる傾向があります。 intとlongは最も変化する傾向があり、同じサイズの場合もあれば異なる場合もありますが、要点は想定されていません。
コンパイラのバージョン/ターゲット/コマンドラインオプションのサイズを検出するか、後で問題を最小限に抑えるためにstdintルートを使用するのは簡単です。