Pergunta

enums

são C ++ assinado ou não assinado? E, por extensão, é seguro para validar uma entrada, verificando que é <= seu valor máximo, e deixar de fora> = o valor min (supondo que você começou em 0 e incrementado por 1)?

Foi útil?

Solução

Você não deve confiar em qualquer representação específica. Leia a seguinte ligação . Além disso, a norma diz que é definido implementação em que tipo integral é usado como o tipo subjacente de uma enumeração, exceto que ele não deve ser maior do que int, a menos que algum valor não pode caber em int ou um int não assinado.

Em resumo:. Você não pode confiar em um enum sendo assinados ou não assinados

Outras dicas

Deixe-nos ir à fonte. Aqui está o que o C ++ 03 padrão (ISO / IEC 14882: 2003) documento diz em 7.2-5 (declarações de enumeração):

O tipo subjacente de uma enumeração é um tipo integral que pode representar todos os valores de enumerador definido em a enumeração. Isto é definido de aplicação em que integrante tipo é usado como o tipo subjacente uma enumeração, exceto que o subjacente tipo não deve ser maior do que int a menos que o valor de um enumerador não pode caber em um int ou unsigned int.

Em suma, o seu compilador começa a escolher (obviamente, se você tem os números negativos para alguns de seus valores ennumeration, vai ser assinado).

Você não deve depender deles a ser assinado ou não assinado. Se você quiser torná-los explicitamente assinado ou não assinado, você pode usar o seguinte:

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

Você não deve contar com ele sendo assinados ou não assinados. De acordo com o padrão é definido pela implementação que tipo integral é usado como o tipo de base para um enum. Na maioria das implementações, porém, é um inteiro assinado.

Em C ++ 0x enumerações rigidez será acrescentado que permitirá que você especifique o tipo de um enum, tais como:

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

Mesmo agora, no entanto, alguma validação simples pode ser alcançada usando o enum como uma variável ou parâmetro de tipo assim:

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.

O compilador pode decidir se quer ou não enums são assinados ou não assinados.

Outro método de validação enums é usar-se a enumeração como um tipo de variável. Por exemplo:

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.

Mesmo algumas respostas velhas tem 44 upvotes, que tendem a discordar com todos eles. Em suma, eu não acho que devemos nos preocupar com o underlying type do enum.

Primeiro, C ++ 03 tipo Enum é um tipo distinto de seu próprio ter nenhum conceito de sinal. Desde de C ++ 03 dcl.enum padrão

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

Então, quando nós estamos falando sobre o sinal de um tipo enum, dizer ao comparar 2 operandos enum usando o operador <, na verdade estamos falando implicitamente converter o tipo enum a algum tipo integral. É o sinal deste tipo integral que importa . E ao converter enum para tipo integral, esta afirmação aplica-se:

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

E, aparentemente, o tipo subjacente da enumeração get nada a ver com a Promoção Integral. Uma vez que os norma define Promoção Integral assim:

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.

Assim, se um tipo de enumeração torna-se signed int ou unsigned int depende se signed int pode conter todos os valores dos recenseadores definidos, não o tipo subjacente da enumeração.

Veja a minha pergunta relacionada de C ++ Enum tipo incorreto após converter a Integral Digite

No futuro, com C ++ 0x, fortemente digitado enumerações estarão disponíveis e têm várias vantagens (como tipo de segurança, tipos subjacentes explícitas, ou escopo explícito). Com isso você poderia ser mais bem assegurado do sinal do tipo.

Além do que outros já disseram sobre assinado / sem assinatura, aqui está o que a norma diz sobre a gama de um tipo enumerado:

7.2 (6): "Para uma enumeração em que e (min) é o menor entrevistador e e (max) é o maior, os valores de enumeração são os valores do tipo subjacente na gama b (min) para b (max), em que b (min) e b (max) são, respectivamente, os valores menores e maiores do menor campo de bits que pode armazenar e (min) e e (máx). é possível definir uma enumeração que possui valores não definidos por qualquer de seus entrevistadores ".

Assim, por exemplo:

enum { A = 1, B = 4};

define um tipo enumerado, onde e (min) é 1 e E (max) é 4. Se o tipo subjacente é assinado int, então a menor bitfield necessária tem 4 bits, e complemento se ints em sua implementação são duas de então o intervalo válido da enumeração é -8 a 7. Se o tipo subjacente não está assinado, então ele tem 3 bits eo intervalo é de 0 a 7. Verifique a documentação do compilador se você se importa (por exemplo, se você quiser lançar diferentes valores integrais recenseadores para o tipo enumerado, então você precisa saber se o valor está na faixa da enumeração ou não -. Se não o valor enum resultante é não especificado)

Se esses valores são de entrada válida para a sua função pode ser uma questão diferente se eles são os valores válidos do tipo enumerado. Seu código de verificação é provavelmente preocupado com o antigo, em vez do último, e assim neste exemplo deve pelo menos ser verificando> = A e <= B.

Verifique com std::is_signed<std::underlying_type + escopo enums padrão para 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 montante .

compilar e executar:

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

Output:

0

Testado no Ubuntu 16.04, GCC 6.4.0.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top