3

質問

Cで行われる一定の折り畳みについて保証があるかどうか、私は興味があります.

私が見たところ

私には評判が不明なサイトのこのリンクは、率直なコメントをしています。

すべての C コンパイラは、マクロ展開後に存在する整数定数式を折りたたむことができます (ANSI C 要件)。

しかし、たとえば The C Programming Language, second edition (ANSI C のすべての詳細を説明するために完全に更新されたと思います) には何も表示されません。しかし、関連する単語への参照のインデックスをチェックした後、これを約束するものは何も見つかりませんでした. 特に38ページと209ページは、コンパイル時に評価できる任意の式を、定数を使用できる場所で使用できると述べているため(十分に知識があれば、おそらくいくつかの制限があります)、そのような式は次のように述べています。 " may " はコンパイル時に評価されますが、"will"/(いくつかの同義語) ではありません。

この C89 最終案を検索しました。"folding" と "folded" という単語では値の結果が得られず、"constant expression" で検索すると 63 件の一致が生成され、そのうちの約半分を調べました。興味のある主要な部分は基本的に本と同じようです ( 「かもしれない」の代わりに「できる」という言葉を使用していますが、この文脈ではそれらは同義です)。

これらはどちらも、すべての ANSI C コンパイラが基本的な定数折りたたみ機能を備えている必要があることを論理的に強く暗示しているように思われますが、同時に、定数式を式を計算するコードにコンパイルすることに対する厳しい禁止事項はないようです。実行時 (このような実装でも、定数式の利点が得られます。これは、コンパイラが定数式を一度計算すると、値が変化しないと想定するコードを生成できるためです。また、そのような実装は、特定の基礎となるアーキテクチャ (たとえば、いくつかの RISC アーキテクチャ) の制限によって強制される可能性があります。可能な値を初期化するために 2 つの命令を使用するか、メモリ位置からそれらをロードする必要があります)。

この C99 最終ドラフトも簡単に検索しましたが、"folding" は価値のない結果を 1 つ得ましたが、"folded" と "constant" にはそれぞれ 100 以上の一致があり、現在クロールする時間を割り当てることができませんでした。

動機

これらのマクロは、ビットをいじるコードでよりセマンティック/意図を明確にするために作成しました。

#define UCHAR_LOW_N_BITS_m(n) (unsigned char )(UCHAR_MAX >> (CHAR_BIT - (n)))
#define UCHAR_NTH_BIT_m(n) (unsigned char )(1 << (n))

..wherenは常に整数リテラルです。私は安心したいのですが、「大丈夫です。リモートで重要な使用中のすべての C コンパイラがこれらの定数を折りたたんでくれます」という安心できる声を聞きたいです。(追記: ビットが 0 番目または 1 番目のビットから始まるUCHAR_NTH_BIT_mかのように動作するかどうかについて、別の質問をしました。できれば適切な場所で行います。)

そして、はい、一番下のものは別のマクロに変えることができます。たとえば、コードでたまたま必要なマクロを#define UCHAR_1ST_BIT_m (unsigned char )1介して#define UCHAR_3RD_BIT_m (unsigned char )4、または必要に応じて多くのマクロを作成できます-そして、それらのどれが優れているかについては未定ですが、おそらく議論の余地があります。優れたペダンティック言語弁護士タイプの C プログラマーになるためには、一番上のものを正確に避けることはできません (これらの DSP/組み込みおよび古代のメインフレーム C 実装でコードが正しいことを実行することを確認する必要があります)。

4

2 に答える 2

7

C 標準では、コンパイル時の用語は変換時間であり、コンパイル時に発生するイベントは変換と記述される場合があります。これらの用語の標準を検索できます。

この標準でトピックに最も近いのは、セクション 6.6 (C11)の定数式の定義です。概要は次のとおりです。

定数式は、実行時ではなく変換中に評価できるため、定数がある場所であればどこでも使用できます。

「できる」というのは、「なくてはならない」という意味ではないことに注意してください。これは絶対的な要件ではありませんが、高品質のコンパイラがコンパイル時に定数式を評価することを期待しています。

セクション 6.6 は大きすぎてすべてをここに貼り付けることができませんが、C 標準 (または N1570 などのドラフト) を参照することで、どの式が定数式として定義されているかを読み取ることができ、コンパイラがそれらをコンパイル時。

n >= 0 && n < CHAR_BIT * sizeof(int) - 1、およびnが整数定数式の場合、(unsigned char )(1 << (n))整数定数式です。その理由は、そのオペランドが整数定数であり、定数式で禁止されている演算子の 1 つ (たとえば ) を使用しておらず++、キャストが許可されているためです。整数型から別の整数型へ。

がこの範囲外の場合n、式は定数式ではなく、未定義の動作を引き起こします。

あなたの他の表現は似ています。CHAR_BIT - n同じ有効範囲内にある限り、ICEです。

于 2016-04-08T08:22:39.670 に答える
5

一般に、C 標準は何かをコンパイルする方法を指定していません。何かを実装する 1 つの方法が別の方法よりも高速であるという保証はありません。定数の折りたたみが必ず発生するという保証はありませんが、コンパイラはコンパイル時に (#ifディレクティブと配列宣言子を処理するために) 定数式を評価できる必要があるため、コンパイラが定数の折りたたみを行う可能性は非常に高くなります。結局のところ、一定の折り畳みができるのにそれをしないのは意味がありません。

于 2016-04-08T08:12:09.077 に答える