2013-03-08 10 views
5

Utilizzando -Wall -pedanticclang enum trabocco

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

int main(void) 
{ 
    enum x { 
     a, 
     max = INT_MAX, 
     out_1 
    }; 
    enum y { 
     b, 
     out_2 = INT_MAX + 1 
    }; 


    printf("%d %d\n", out_1, out_2); 
    return 0; 
} 

clang torna

demo.c:9:3: warning: overflow in enumeration value 
       out_1 
       ^

Come si può vedere, il compilatore non avvisa su trabocco out_2, il suo valore è sconosciuto al momento della compilazione?

+2

Abbastanza sicuro che lo standard non definisca l'intervallo di un 'enum'. – asveikau

+1

La mia ipotesi: prima valuta INT_MAX + 1, che si avvolge e assegna a out_2. –

+1

@johnny: no, richiama UB. –

risposta

1

Nella prima istanza, il compilatore stesso sta provando a selezionare un numero intero che sta causando un overflow, e quindi ti avvisa. È probabile che produca INT_MIN. Lo standard consente a qualsiasi valore in un signed int di essere una costante enum (vedere in basso).

Nel secondo, l'espressione (INT_MAX + 1) viene calcolata prima che venga assegnata a out_2. Un overflow nell'espressione qui sta producendo un risultato che è permesso, ma questo è un comportamento indefinito. Il risultato valido viene quindi memorizzato nell'enumerazione, motivo per cui non viene prodotto il primo errore.

clang (3,2) anche non avvertire di questo, che è effettivamente identica:

int a = INT_MAX + 1; 

A questo proposito, clang non si comporta secondo lo standard C, in quanto questo è indefinito.

L'uscita dal gcc in confronto fa la differenza completamente chiaro:

In function ‘main’: 
9:9: error: overflow in enumeration values 
13:25: warning: integer overflow in expression [-Woverflow] 

Il compilatore Intel ignora l'overflow enum, ma avverte circa l'overflow integer:

enum.c(13): warning #61: integer operation result is out of range 
     out_2 = INT_MAX + 1 
        ^


Per riferimento, dallo standard C99 6.7.7.2.2, "L'espressione che definisce il valore di una costante di enumerazione deve essere un'espressione costante intera che ha un valore rappresentabile come int; .3," T identifica gli elenchi di un elenco di enumeratori come costanti che hanno tipo int e possono apparire ovunque siano consentiti. "Ad esempio, una costante enum può essere qualsiasi valore int e ha un tipo int. Il tipo risultante di una variabile enum definita può essere char, int o unsigned int, purché consenta tutte le possibili costanti nell'enumerazione. Di conseguenza, sia enums nell'esempio non sono definiti, in quanto entrambi richiedono un overflow di numeri interi. Il primo è esplicitamente illegale.

+0

Ma la domanda era: perché Clang ** non ** avvisa di out_2. –

+0

@eznme: il secondo punto - il numero intero è un enum valido dopo che l'espressione è stata calcolata, in questo caso. – teppic

+1

@eznme Direi che è perché "-Wall" è un termine improprio. Con '-Weverything', o probabilmente anche' -Wextra', mi aspetterei clang di avvertire sull'overflow. –

0

ISO C specifica gli interi come valori enum.

Se il compilatore lo consente (e GCC e Clang fanno), allora INT_MIN è un valore perfettamente valido.

Se il compilatore non avrebbe permesso un indice specificato problema, allora è necessario un errore.

Il motivo per cui un INT_MIN esplicitamente richiesto va bene, ma un valore auto-aumentato dal predecessore INT_MAX emette un avvertimento è, che la norma richiede +1 Comportamento.

+0

ma le costanti 'enum' sono' int'. – ouah

+0

@ouah si come ho detto. (la quarta parola che ho usato) –

+0

quindi ammetti che una costante 'enum' di' INT_MIN' deve essere accettata da tutti i compilatori C? – ouah