C++ 列挙型は署名されていますか?それとも署名されていませんか?

StackOverflow https://stackoverflow.com/questions/159034

  •  03-07-2019
  •  | 
  •  

質問

C++ 列挙型は署名されていますか?それとも署名されていませんか?さらに言えば、入力が最大値以下であることを確認し、最小値以上を除外することによって入力を検証するのは安全ですか (0 から開始して 1 ずつ増加すると仮定します)。

役に立ちましたか?

解決

特定の表現に頼るべきではありません。次のリンクをお読みください。また、標準では、一部の値がintまたはunsigned intに収まらない場合を除き、intより大きくてはならないことを除き、enumの基になる型として使用される整数型は実装定義であると述べています。

要するに、enumが署名されているか署名されていないかに依存することはできません。

他のヒント

ソースに行きましょう。 C ++ 03標準(ISO / IEC 14882:2003)ドキュメントの7.2-5(列挙宣言)の内容は次のとおりです。

  

列挙の基本型   表現できる整数型です   で定義されているすべての列挙子の値   列挙。それは   実装定義のどの積分   タイプは基礎となるタイプとして使用されます   を除く列挙   基になる型は大きくてはならない   の値が   列挙子はintまたは   符号なし整数。

要するに、コンパイラは選択できるようになります(明らかに、いくつかの列挙値に負の数がある場合、符号が付けられます)。

署名または署名なしに依存するべきではありません。明示的に署名または署名なしにする場合は、次を使用できます。

enum X : signed int { ... };    // signed enum
enum Y : unsigned int { ... };  // unsigned enum

署名されているか署名されていないかに依存すべきではありません。標準によれば、どの整数型が列挙型の基本型として使用されるかは、実装で定義されています。ただし、ほとんどの実装では、符号付き整数です。

C ++ 0xでは、厳密に型指定された列挙が追加されます。次のような列挙型を指定できます。

enum X : signed int { ... };    // signed enum
enum Y : unsigned int { ... };  // unsigned enum

しかし、今でも、enumを次のような変数またはパラメータータイプとして使用することで、いくつかの簡単な検証を実現できます。

enum Fruit { Apple, Banana };

enum Fruit fruitVariable = Banana;  // Okay, Banana is a member of the Fruit enum
fruitVariable = 1;  // Error, 1 is not a member of enum Fruit
                    // even though it has the same value as banana.

コンパイラは、enumが署名されているかどうかを判断できます。

enumを検証するもう1つの方法は、enum自体を変数型として使用することです。例:

enum Fruit
{
    Apple = 0,
    Banana,
    Pineapple,
    Orange,
    Kumquat
};

enum Fruit fruitVariable = Banana;  // Okay, Banana is a member of the Fruit enum
fruitVariable = 1;  // Error, 1 is not a member of enum Fruit even though it has the same value as banana.

いくつかの古い回答でも 44 の賛成票が得られましたが、私はそれらすべてに反対する傾向があります。要するに、気にする必要はないと思います underlying type 列挙型の。

まず、C++03 Enum 型は、符号の概念を持たない独自の型です。C++03標準以降 dcl.enum

7.2 Enumeration declarations 
5 Each enumeration defines a type that is different from all other types....

したがって、列挙型の符号について話しているとき、たとえば、 < 演算子では、実際には enum 型を整数型に暗黙的に変換することについて話しています。 重要なのはこの積分型の符号です. 。enum を整数型に変換する場合、次のステートメントが適用されます。

9 The value of an enumerator or an object of an enumeration type is converted to an integer by integral promotion (4.5).

そして、明らかに、列挙型の基になる型は統合プロモーションとは何の関係もありません。標準では統合プロモーションが次のように定義されているため、

4.5 Integral promotions conv.prom
.. An rvalue of an enumeration type (7.2) can be converted to an rvalue of the first of the following types that can represent all the values of the enumeration
(i.e. the values in the range bmin to bmax as described in 7.2: int, unsigned int, long, or unsigned long.

したがって、列挙型が次になるかどうかは、 signed int または unsigned int かどうかによります signed int 列挙型の基礎となる型ではなく、定義された列挙子のすべての値を含めることができます。

私の関連する質問を参照してください整数型に変換した後の C++ 列挙型の符号が正しくない

将来、C ++ 0xを使用して、強く型付けされた列挙が利用可能になり、いくつかの利点があります(型安全性、明示的な基本型、明示的なスコープなど)。これにより、型の符号をより確実に確認できます。

他の人が既に署名/署名なしについて述べていることに加えて、標準は列挙型の範囲について言っています:

7.2(6):<!> quot; e(min)が最小の列挙子で、e(max)が最大の列挙の場合、列挙の値は、範囲bの基になる型の値です。 (min)からb(max)。ここで、b(min)とb(max)は、それぞれ、e(min)とe(max)を格納できる最小ビットフィールドの最小値と最大値です。列挙子によって定義されていない値を持つ列挙を定義することができます。<!> quot;

したがって、たとえば:

enum { A = 1, B = 4};

は、e(min)が1でe(max)が4の列挙型を定義します。基になる型が符号付きintの場合、必要な最小ビットフィールドは4ビットで、実装のintが2の補数の場合列挙型の有効範囲は-8〜7です。基になる型が符号なしの場合、3ビットで範囲は0〜7です。気にする場合はコンパイラのドキュメントを確認してください(たとえば、列挙型の列挙子、値が列挙の範囲内にあるかどうかを知る必要があります-結果の列挙値が指定されていない場合)

これらの値が関数への有効な入力であるかどうかは、列挙型の有効な値であるかどうかとは異なる問題になる可能性があります。あなたのチェックコードはおそらく後者ではなく前者を心配しているので、この例では少なくとも<!> gt; = Aと<!> lt; = Bをチェックする必要があります。

std::is_signed<std::underlying_type +有効範囲付き列挙型をデフォルトでint

でチェックします

https://en.cppreference.com/w/cpp/language/enum の意味:

main.cpp

#include <cassert>
#include <iostream>
#include <type_traits>

enum Unscoped {};
enum class ScopedDefault {};
enum class ScopedExplicit : long {};

int main() {
    // Implementation defined, let's find out.
    std::cout << std::is_signed<std::underlying_type<Unscoped>>() << std::endl;

    // Guaranteed. Scoped defaults to int.
    assert((std::is_same<std::underlying_type<ScopedDefault>::type, int>()));

    // Guaranteed. We set it ourselves.
    assert((std::is_same<std::underlying_type<ScopedExplicit>::type, long>()));
}

GitHubアップストリーム

コンパイルして実行:

g++ -std=c++17 -Wall -Wextra -pedantic-errors -o main main.cpp
./main

出力:

0

Ubuntu 16.04、GCC 6.4.0でテスト済み。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top