objetos Constantes Enum se comportando de maneira diferente em C e C++



how different is c from c++ (4)

Por que isso:

#include <stdio.h>
#include <limits.h>
#include <inttypes.h>

int main() {
    enum en_e {
        en_e_foo,
        en_e_bar = UINT64_MAX,
    };
    enum en_e e = en_e_foo;
    printf("%zu\n", sizeof en_e_foo);
    printf("%zu\n", sizeof en_e_bar);
    printf("%zu\n", sizeof e);
}

imprimir 4 8 8 em C e 8 8 8 em C ++ (em uma plataforma com ints de 4 bytes)?

Fiquei com a impressão de que a atribuição UINT64_MAX forçaria todas as constantes de enumerações a pelo menos 64 bits, mas en_e_foo permanece em 32 na planície C.

Qual é a razão para a discrepância?

https://ffff65535.com


C11 - 6.7.2.2/2

A expressão que define o valor de uma constante de enumeração deve ser uma expressão constante inteira que tenha um valor representável como um int .

en_e_bar=UINT64_MAX é uma violação de restrição e isso torna o código acima inválido. Uma mensagem de diagnóstico deve ser produzida confirmando a implementação como indicado no esboço C11:

Uma implementação conforme deverá produzir pelo menos uma mensagem de diagnóstico (identificada de maneira definida pela implementação) se uma unidade de tradução de pré-processamento ou uma unidade de tradução contiver uma violação de qualquer regra ou restrição de sintaxe, [...]

Parece que o GCC tem algum bug e não conseguiu produzir a mensagem de diagnóstico. (Bug é apontado na answer por Grzegorz Szpetkowski


Como outros apontaram, o código é mal formado (em C), devido à violação de restrição.

Existe o bug GCC https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71613 (relatado em junho de 2016), que afirma que alguns avisos úteis são silenciados com macros.

Avisos úteis parecem ser silenciados quando macros de cabeçalhos de sistema são usados. Por exemplo, no exemplo abaixo, um aviso seria útil para as duas enums, mas apenas um aviso é exibido. O mesmo pode acontecer com outros avisos.

A solução atual pode ser prefixar a macro com o operador unary + :

enum en_e {
   en_e_foo,
   en_e_bar = +UINT64_MAX,
};

que produz erro de compilação na minha máquina com o GCC 4.9.2:

$ gcc -std=c11 -pedantic-errors -Wall main.c 
main.c: In function main’:
main.c:9:20: error: ISO C restricts enumerator values to range of int [-Wpedantic]
         en_e_bar = +UINT64_MAX

Em C, uma constante de enum é do tipo int . Em C ++, é do tipo enumerado.

enum en_e{
    en_e_foo,
    en_e_bar=UINT64_MAX,
};

Em C, isso é uma violação de restrição , exigindo um diagnóstico ( se o UINT64_MAX exceder o UINT64_MAX , o que é muito provável). O compilador AC pode rejeitar completamente o programa ou pode imprimir um aviso e gerar um executável cujo comportamento é indefinido. (Não é 100% claro que um programa que viola uma restrição necessariamente tem um comportamento indefinido, mas neste caso o padrão não diz qual é o comportamento, então isso ainda é um comportamento indefinido.)

O gcc 6.2 não avisa sobre isso. clang faz. Este é um bug no gcc; Inadequadamente inibe algumas mensagens de diagnóstico quando macros de cabeçalhos padrão são usados. Obrigado a Grzegorz Szpetkowski por localizar o relatório do bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71613

Em C ++, cada tipo de enumeração tem um tipo subjacente , que é algum tipo inteiro (não necessariamente int ). Esse tipo subjacente deve ser capaz de representar todos os valores constantes. Portanto, nesse caso, en_e_foo e en_e_bar são do tipo en_e , que devem ter pelo menos 64 bits de largura, mesmo que int seja mais estreito.


Esse código só não é válido C em primeiro lugar.

Seção 6.7.2.2 em ambos C99 e C11 diz que:

Restrições:

A expressão que define o valor de uma constante de enumeração deve ser uma expressão constante inteira que tenha um valor representável como um int .

Um diagnóstico de compilador é obrigatório porque é uma violação de restrição, consulte 5.1.1.3:

Uma implementação conforme deverá produzir pelo menos uma mensagem de diagnóstico (identificada de uma maneira definida pela implementação) se uma unidade de tradução ou unidade de tradução pré-processamento contiver uma violação de qualquer regra ou restrição de sintaxe, mesmo se o comportamento também for explicitamente especificado como indefinido ou implementado. definiram.





c