web-dev-qa-db-ja.com

boolを0に設定しても安全ですか?

bugが発見されない限り変更できないlegacyコードがあり、次のコードが含まれているとします。

bool data[32];
memset(data, 0, sizeof(data));

これは、配列内のすべてのboolfalse値に設定する安全な方法ですか?

より一般的には、値をmemsetにするために、bool a falseから0に安全ですか?

すべてのコンパイラで動作することが保証されていますか?または、修正をリクエストしますか?

32
Neil Kirk

falseの基底表現はすべてゼロになる可能性が高いと思われますが、これは特定されていないと思います。 Boost.Containerもこれに依存していますemphasis mine):

Boost.Containerは、ゼロ値のstd :: memsetを使用して一部のタイプを初期化します。ほとんどのプラットフォームでは、この初期化により、パフォーマンスが向上した目的の値の初期化が行われます。

C11標準に従い、Boost.Containerは、任意の整数型について、すべてのビットがゼロであるオブジェクト表現は、その型の値ゼロの表現であると想定しています。 _ Bool/wchar_t/char16_t/char32_tもCの整数型であるため、すべてのC++整数型をstd :: memsetを介して初期化可能と見なします。

理論的根拠として彼らが指摘しているこのC11の引用は、実際にはC99の欠陥から来ています: 欠陥263:すべてゼロのビット表現 これは以下を追加しました:

任意の整数型の場合、すべてのビットがゼロであるオブジェクト表現は、その型の値ゼロの表現でなければなりません。

それで、ここでの質問は正しい仮定です、整数の基礎となるオブジェクト表現はCとC++の間で互換性がありますか?提案 整数のオブジェクト表現に関するCとC++の違いを解決する これにある程度答えようとしましたが、私が知る限りでは解決されませんでした。ドラフト標準では、これの決定的な証拠を見つけることができません。タイプに関してC標準に明示的にリンクするケースがいくつかあります。セクション3.9.1[basic.fundamental]は次のように述べています。

[...]符号付きおよび符号なし整数型は、C標準のセクション5.4.2.2.1で指定されている制約を満たさなければなりません。

および3.9[basic.types]これは次のように述べています。

タイプTのオブジェクトのオブジェクト表現は、タイプTのオブジェクトによって取得されるN個のunsigned charオブジェクトのシーケンスです。ここで、Nはsizeof(T)に等しくなります。オブジェクトの値表現は、タイプTの値を保持するビットのセットです。簡単にコピー可能なタイプの場合、値表現は、実装の1つの個別要素である値を決定するオブジェクト表現のビットのセットです。定義された値のセット。44

ここで、脚注44(これは規範的ではありません)は次のように述べています:

その意図は、C++のメモリモデルがISO/IEC9899プログラミング言語Cのメモリモデルと互換性があることです。

ドラフト標準がboolの基底表現を指定するのに最も遠いのは、セクション3.9.1にあります。

タイプbool、char、char16_t、char32_t、wchar_t、および符号付きと符号なしの整数型は、まとめて整数型と呼ばれます。50整数型の同義語は整数型です。整数型の表現は、純粋な2進記数法を使用して値を定義するものとします51。[例:この国際規格では、整数型の2の補数、1の補数、および符号付きの大きさの表現が許可されています。 —例を終了]

セクションはまた言う:

タイプboolの値はtrueまたはfalseのいずれかです。

しかし、truefalseについて知っているのは次のとおりです。

ブールリテラルは、キーワードfalseおよびtrueです。このようなリテラルはprvaluesであり、bool型を持ちます。

そして、それらが0 an 1に変換可能であることを私たちは知っています。

Bool型のprvalueは、int型のprvalueに変換でき、falseは0になり、trueは1になります。

しかし、これは私たちを基礎となる表現に近づけません。

私が知る限り、標準がパディングビット以外の実際の基になるビット値を参照する唯一の場所は 欠陥レポート1796:ヌル文字のall-bits-zeroは意味のある要件ですか?

ポータブルプログラムが表現のビットを調べることができるかどうかは明らかではありません。代わりに、値の表現に対応する数値のビットを調べることに限定されているように見えます(3.9.1 [basic.fundamental]段落1)。表現のビットパターンを指定するよりも、ヌル文字値を0または「\ 0」と等しくするように要求する方が適切な場合があります。

さらに 欠陥レポート は、値とオブジェクト表現のビットと違いに関する標準のギャップを処理します。

実際には、これが機能することを期待しますが、標準ではこれを特定できないため、安全だとは思いません。明確ではなく、変更する必要がありますか。明らかに、重要なトレードオフが関係しています。したがって、現在機能していると仮定すると、問題は、さまざまなコンパイラの将来のバージョンで機能しなくなる可能性があると考えるかどうかです。これは不明です。

7
Shafik Yaghmour

法律で保証されていますか?いいえ

C++は、bool値の表現については何も述べていません。

実際の現実によって保証されていますか?はい。

つまり、ブール値のfalseをゼロのシーケンスとして表さないC++実装を見つけたい場合は、幸運を祈ります。 falseは暗黙的に0に変換する必要があり、trueは暗黙的に1に変換する必要があり、0は暗黙的にfalseに変換する必要があり、非0は暗黙的にtrueに変換する必要があります。

それが「安全」であることを意味するかどうかは、あなたが決めることです。

私は通常これを言いませんが、私があなたの状況にあったら、私はこのスライドをさせていただきたいと思います。本当に心配な場合は、実際のプロジェクトをインストールする前に、テスト実行可能ファイルをディストリビューターに追加して、各ターゲットプラットフォームの前提条件を検証できます。

いいえ安全ではありません(より具体的には、ポータブルです)。ただし、通常の実装では次のようになるため、は機能する可能性があります

  1. ブール値を表すには0を使用します(実際には、C++仕様ではブール値が必要です)
  2. memset()が処理できる要素の配列を生成します。

ただし、ベストプラクティスでは、_bool data[32] = {false}_を使用する必要があります。さらに、これにより、コンパイラが解放され、構造を内部的に異なる方法で表現できるようになります。memset()を使用すると、32バイトの値の配列が生成される可能性があるためです。たとえば、平均的なCPUレジスタにうまく収まる単一の4バイトよりも。

9
Olipro

3.9.1/7から:

タイプbool、char、char16_t、char32_t、wchar_t、および符号付き整数型と符号なし整数型は、まとめて整数型と呼ばれます。整数型の同義語は整数型です。整数型の表現は、純粋な2進記数法を使用して値を定義するものとします。

これを考えると、すべての0ビットとしてfalseを表さないboolの可能な実装は見当たりません。

8
Mark B