Domanda

Sono C++ enumerazioni signed o unsigned?E, per estensione, è sicuro per convalidare l'input controllando che è <= il valore massimo, e lasciare fuori >= il valore min (supponendo che hai iniziato a 0 e viene incrementato di 1)?

È stato utile?

Soluzione

Non devi fare affidamento su alcuna rappresentazione specifica. Leggi il seguente link . Inoltre, lo standard afferma che è definito dall'implementazione quale tipo integrale viene utilizzato come tipo sottostante per un enum, tranne per il fatto che non deve essere più grande di int, a meno che un valore non possa rientrare in int o in un unsigned int.

In breve: non puoi fare affidamento sul fatto che un enum sia firmato o non firmato.

Altri suggerimenti

Andiamo alla fonte. Ecco cosa dice il documento standard C ++ 03 (ISO / IEC 14882: 2003) in 7.2-5 (Dichiarazioni di enumerazione):

  

Il tipo sottostante di un'enumerazione   è un tipo integrale che può rappresentare   tutti i valori dell'enumeratore definiti in   l'enumerazione. È   implementazione definita quale integrale   tipo viene utilizzato come tipo sottostante   per un elenco tranne che il   il tipo sottostante non deve essere più grande   di int a meno che il valore di an   l'enumeratore non può rientrare in un int o   unsigned int.

In breve, il tuo compilatore può scegliere (ovviamente, se hai numeri negativi per alcuni dei tuoi valori di enumerazione, verrà firmato).

Non dovresti dipendere dal fatto che siano firmati o non firmati. Se desideri renderli esplicitamente firmati o non firmati, puoi utilizzare quanto segue:

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

Non devi fare affidamento sul fatto che sia firmato o non firmato. Secondo lo standard viene definito l'implementazione quale tipo integrale viene utilizzato come tipo sottostante per un enum. Nella maggior parte delle implementazioni, tuttavia, è un numero intero con segno.

In C ++ 0x saranno aggiunte enumerazioni fortemente tipizzate ti permetterà di specificare il tipo di enum come:

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

Anche ora, tuttavia, è possibile ottenere una semplice convalida utilizzando l'enum come variabile o tipo di parametro come questo:

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.

Il compilatore può decidere se gli enum sono firmati o meno.

Un altro metodo per convalidare gli enum è usare l'enum stesso come tipo variabile. Ad esempio:

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.

Anche alcune vecchie risposte hanno ottenuto 44 voti, tendo a non essere d'accordo con tutti loro. In breve, non penso che dovremmo preoccuparci del underlying type dell'enum.

Prima di tutto, C ++ 03 Enum type è un tipo distinto a sé stante che non ha alcun concetto di segno. Da dallo standard C ++ 03 dcl.enum

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

Quindi quando parliamo del segno di un tipo di enum, diciamo quando confrontiamo 2 operandi di enum usando l'operatore <, stiamo effettivamente parlando di convertire implicitamente il tipo di enum in un tipo integrale. È il segno di questo tipo integrale che conta . E quando si converte enum in tipo integrale, si applica questa affermazione:

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

E, a quanto pare, il tipo di base dell'enum non ha nulla a che fare con la promozione integrale. Poiché lo standard definisce la promozione integrale in questo modo:

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.

Quindi, se un tipo di enum diventa signed int o unsigned int dipende dal fatto che <=> possa contenere tutti i valori degli enumeratori definiti, non il tipo sottostante dell'enum.

Vedi la mia domanda correlata Segno di C ++ Enum Type errato dopo la conversione in integrale Tipo

In futuro, con C ++ 0x, enumerazioni fortemente tipizzate sarà disponibile e presenterà numerosi vantaggi (come la sicurezza dei tipi, i tipi espliciti sottostanti o l'ambito esplicito). Con ciò potresti essere più sicuro del segno del tipo.

In aggiunta a ciò che altri hanno già detto con/senza segno, ecco che cosa lo standard dice circa la portata di un tipo enumerato:

7.2(6):"Per un'enumerazione, dove e(min) è il più piccolo enumeratore e e(max) è il più grande, i valori dell'enumerazione sono i valori del sottostante digitare la gamma b(min) b(max) b(min) b(max) sono, rispettivamente, il più piccolo e il più grande dei valori di un piccolo campo di bit che consente di memorizzare e(min) e e(max).È possibile definire un'enumerazione che ha i valori non definiti da uno qualsiasi dei suoi enumeratori."

Così, per esempio:

enum { A = 1, B = 4};

definisce un tipo enumerato, dove e(min) (1) e(max) è di 4.Se il sottostante è di tipo signed int, più piccola, è richiesto di bit dispone di 4 bit, e se ints nell'implementazione sono in complemento a due, quindi l'intervallo valido di enum è da -8 a 7.Se il sottostante è di tipo unsigned, quindi ha 3 pezzi e la gamma da 0 a 7.Controllare la documentazione del compilatore se ti interessa (per esempio, se si desidera cast integrale valori diversi da quelli enumeratori per il tipo enumerato, allora avete bisogno di sapere se il valore è compreso nell'intervallo di enumerazione o meno - se non il risultante valore di enumerazione non è specificato).

Se tali valori sono validi input alla funzione potrebbe essere un problema diverso da se sono valori validi per il tipo enumerato.Il tuo codice di verifica è probabilmente preoccupato per l'ex piuttosto che il secondo, e quindi, in questo esempio dovrebbe essere almeno di controllo >=A e <=B.

Verifica con std::is_signed<std::underlying_type + enumerazioni con ambito predefiniti su int

https://en.cppreference.com/w/cpp/language/enum implica:

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 upstream Compila ed esegui:

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

Output:

0

Testato su Ubuntu 16.04, GCC 6.4.0.

scroll top