2013-03-08 33 views
5

Sử dụng Wall -pedantickêu vang enum tràn

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

kêu vang trả

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

Như bạn có thể thấy, trình biên dịch không cảnh báo về tràn out_2, giá trị của mình là chưa có thời gian biên dịch?

+2

Khá chắc chắn tiêu chuẩn không xác định phạm vi 'enum'. – asveikau

+1

Đoán của tôi: nó đánh giá INT_MAX + 1 trước tiên, nó sẽ bao quanh và gán nó cho out_2. –

+1

@ johnny: không, nó gọi UB. –

Trả lời

1

Trong trường hợp đầu tiên, bản thân trình biên dịch đang cố gắng chọn một số nguyên đang gây tràn, và do đó cảnh báo bạn. Nó có khả năng sản xuất INT_MIN. Chuẩn cho phép bất kỳ giá trị nào trong một signed int là hằng số enum (xem dưới).

Trong giây, biểu thức (INT_MAX + 1) được tính trước khi được gán cho out_2. Một tràn trong biểu thức ở đây là tạo ra một kết quả được cho phép, nhưng đây là hành vi không xác định. Kết quả hợp lệ sau đó được lưu trữ trong enum, đó là lý do tại sao lỗi đầu tiên không được tạo ra.

kêu vang (3.2) cũng sẽ không cảnh báo về vấn đề này, đó là một cách hiệu quả giống hệt nhau:

int a = INT_MAX + 1; 

Trong khía cạnh này, kêu vang là không hành xử theo tiêu chuẩn C, vì đây là không xác định.

Kết quả từ gcc so nên sự khác biệt hoàn toàn rõ ràng:

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

Trình biên dịch Intel bỏ qua tràn enum, nhưng cảnh báo về sự tràn số nguyên:

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


Để tham khảo, từ tiêu chuẩn C99 6.7.7.2.2, "Biểu thức xác định giá trị của hằng số liệt kê phải là một biểu thức hằng số nguyên có giá trị biểu thị là int; .3," T người nhận dạng trong danh sách liệt kê được khai báo là hằng số có loại int và có thể xuất hiện ở bất kỳ nơi nào được phép. "tức là hằng số enum có thể là bất kỳ giá trị int nào và có loại int. Loại kết quả của biến số enum được xác định có thể là char, int hoặc unsigned int, miễn là nó cho phép tất cả các hằng số có thể có trong enum. Như vậy cả hai enums trong ví dụ là không xác định, vì cả hai đều yêu cầu tràn số nguyên. Đầu tiên là bất hợp pháp một cách rõ ràng.

+0

Nhưng câu hỏi là: tại sao Clang ** không ** cảnh báo về out_2. –

+0

@eznme: điểm thứ hai - số nguyên là một enum hợp lệ sau khi biểu thức được tính toán, trong trường hợp này. – teppic

+1

@eznme Tôi đoán đó là vì '-Wall' là một từ sai. Với '-Weverything', hoặc thậm chí là' -Wextra', tôi mong đợi clang cảnh báo về tràn. –

0

ISO C chỉ định các số nguyên làm giá trị enum.

Nếu trình biên dịch của bạn cho phép nó (và GCC và Clang làm) thì INT_MIN là một giá trị hoàn toàn tốt.

Nếu trình biên dịch sẽ không cho phép một chỉ số được chỉ định thì yêu cầu phải xuất hiện lỗi .

Lý do tại sao một INT_MIN yêu cầu một cách rõ ràng là tốt nhưng giá trị tự động tăng từ người tiền nhiệm INT_MAX đưa ra một cảnh báo là, tiêu chuẩn đòi hỏi Behavior.

+0

nhưng hằng số 'enum' là' int'. – ouah

+0

@ouah có như tôi đã nói. (từ thứ 4 tôi đã sử dụng) –

+0

để bạn thừa nhận hằng số 'enum' của' INT_MIN' phải được tất cả các trình biên dịch C chấp nhận? – ouah

Các vấn đề liên quan