2013-03-08 12 views
5

Korzystanie -Wall -pedanticdzyń enum przelewowy

#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; 
} 

szczęk zwraca

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

Jak widać, kompilator nie ostrzega o out_2 przelewem, jego wartość nie jest znany w czasie kompilacji?

+2

Jestem pewien, że standard nie definiuje zakresu "wyliczenia". – asveikau

+1

Moje przypuszczenie: najpierw ocenia INT_MAX + 1, które zawija i przypisuje je do out_2. –

+1

@johnny: nie, wywołuje UB. –

Odpowiedz

1

W pierwszej instancji sam kompilator próbuje wybrać liczbę całkowitą, która powoduje przepełnienie, a więc ostrzega. Prawdopodobnie produkuje INT_MIN. Standard pozwala, aby dowolna wartość w signed int była stała enum (patrz na dole).

W drugim wyrażeniu (INT_MAX + 1) oblicza się przed przypisaniem do out_2. Przepełnienie wyrażenia tutaj daje wynik, który jest dozwolony, ale jest to niezdefiniowane zachowanie. Prawidłowy wynik jest następnie zapisywany w wyliczeniu, dlatego pierwszy błąd nie jest generowany.

szczęk (3.2) również nie ostrzega o tym, co jest praktycznie identyczne:

int a = INT_MAX + 1; 

Pod tym względem szczęk nie zachowuje się zgodnie ze standardem C, ponieważ jest zdefiniowana.

Wyjście z gcc w porównaniu czyni różnicę całkowicie jasne:

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

Intel Kompilator ignoruje przepełnienie enum, ale ostrzega o przepełnienie liczby całkowitej:

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


odsyłającym ze standardu C99 6.7.7.2.2, "Wyrażenie określające wartość stałej wyliczeniowej musi być wyrażeniem stałym w postaci liczby całkowitej, które ma wartość reprezentowalną jako int; .3," T Identyfikatory na liście wyliczeniowej są zadeklarowane jako stałe, które mają typ int i mogą pojawić się tam, gdzie są one dozwolone. "tj. stała wyliczeniowa może być dowolną wartością int i ma typ int. Wynikowy typ zdefiniowanej zmiennej wyliczeniowej może być char, int lub unsigned int, o ile pozwala na wszystkie możliwe stałe w wyliczeniu. W związku z tym zarówno enums w tym przykładzie są niezdefiniowane, ponieważ oba wymagają przepełnienia liczby całkowitej. Pierwszy jest wyraźnie nielegalny.

+0

Ale pytanie brzmiało: dlaczego Clang ** nie ** ostrzegają o out_2. –

+0

@eznme: drugi punkt - liczba całkowita jest poprawnym wyliczeniem po wyliczeniu wyrażenia, w tym przypadku. – teppic

+1

@eznme Przypuszczam, że to dlatego, że '-Wall' jest błędnym określeniem. Z '-Weverything' lub prawdopodobnie nawet' -Wextra', oczekiwałbym, że bój ostrzega o przepełnieniu. –

0

ISO C określa liczby całkowite jako wartości wyliczone.

Jeśli twój kompilator na to zezwala (i GCC i Clang), to INT_MIN jest idealnie cienką wartością.

Jeśli kompilator nie pozwoli na przydzieliłeś indeksu, wymagane jest komunikat błędu.

Powodem dlaczego zażądał wyraźnie INT_MIN jest w porządku, ale wartość auto wzrosła od poprzednika INT_MAX wystawia ostrzeżenie jest, że norma wymaga +1 zachowanie.

+0

, ale stałe 'enum' to' int'. – ouah

+0

@ Tak, tak jak powiedziałem. (czwarte słowo użyłem) –

+0

, więc przyznajesz, że stała "wyliczeniowa" dla 'INT_MIN' musi zostać zaakceptowana przez wszystkie kompilatory C? – ouah

Powiązane problemy