c99で長く長い

Jan 10 2021

C99標準では、彼らはを導入しましたlong long。これの目的は何ですか?私の(限られた)Cプログラミングの経験では、4バイトのintと8バイトの長さしか見たことがありません。たとえば、コンパイラエクスプローラから:

場合はlong、すでにある8そして、なぜそれが別追加する必要があるlong longタイプ?これはコンパイラ/アーキテクチャに何をしますか?

回答

6 chux-ReinstateMonica Jan 10 2021 at 05:36

longがすでに8である場合、なぜ別のlong long型を追加する必要があるのですか?これはコンパイラ/アーキテクチャに何をしますか?

「longがすでに8の場合」は、32ビットlongおよびint32ビットまたは16ビットに依存するコードが存在するため、常に当てはまるとは限りません。

long64ビットとして要求すると、コードベースが破損します。これは大きな懸念事項です。


ただし、long32ビットのままにする必要がある(およびしないlong long)必要がある場合は、標準の64ビット整数にアクセスできませんlong long。したがって、の論理的根拠があります。

可能long32ビットまたは64ビット(または他のもの)のいずれかが遷移を可能にするように。

さまざまな関数がのlongように受け渡し/返しfseek(), ftell()ます。long大きなファイルをサポートするために32ビット以上であるという利点があります。

推奨される方法は、より広い範囲を推奨します。「実装がこれを必要とするのに十分な大きさのオブジェクトをサポートしない限り、long使用される型size_tptrdiff_tそれよりも大きい整数変換ランクを持つべきではありませんsigned long int。」これは、32ビットを超えるメモリサイズに関連しています。


おそらく将来的には、実装はint/long/long long/intmax_t32/64/128/256ビットとして使用される可能性があります。

IAC、固定幅タイプのintN_t人気がlongとよりも高まっているのがわかりlong longます。私は固定幅のタイプを使用する傾向があるかbool、( )、unsigned / 、、( )及び休暇(、 )(、) (、 )特別な場合のために。charintunsignedsize_tuintmax_tsigned charunsignedshortunsignedlongunsignedlong long

4 dbush Jan 10 2021 at 05:26

C標準はint、alongが(大まかに言えば)2バイト、aが4バイト、along longが8バイトであることを保証するだけです。

実際、MSVClongは4バイトintですが、それでも4バイトを使用します。

3 NateEldredge Jan 10 2021 at 05:38

intandlongに関連する唯一の要件は、当時と現在、int少なくとも16ビットでlongあり、少なくとも32ビットである必要があるということです。16ビットシステムと32ビットシステムはどちらも32ビットlongである傾向があり、64ビットマシンは1990年代後半にはあまり一般的ではありませんでした。そのため、C99より前は、プログラマーは64ビット整数型を利用できることに移植的に依存することはできませんでした。この問題はlong long、少なくとも64ビットである必要があるの導入によって解決されました。(私はそれがGCCと多分他のコンパイラによって拡張としてすでに提供されたと信じています)。

最近では、多くの(すべてではありませんが)64ビットシステムが64ビットを使用し、それ以上大きくlongする必要がないlong longため、64ビットでもあり、ある意味で冗長です。それらはおそらくあなたが精通しているシステムですが、そこにあるすべてを表すわけではありません。

2 PeterCordes Jan 10 2021 at 10:29

私はあなたがCタイプ幅要件がどのように機能するかについての巨大な間違った仮定を作っていることを認識していなかったと思う:ISO Cは、ちょうど最小値、範囲設定許可されている最小の-大きさのようなLONG_MAXLONG_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 ++を介して許可されるコンパイラーの最適化
old_timer Jan 11 2021 at 06:16

いくつかの制限がありますが、コンパイラーの作成者は、標準の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ルートを使用するのは簡単です。