2010-09-09 32 views
26

Đã chỉnh sửa để bao gồm tham chiếu chuẩn phù hợp nhờ Carl Norum.Số nguyên tràn trong C: tiêu chuẩn và trình biên dịch

tiêu chuẩn quốc

C

Nếu một điều kiện đặc biệt xảy ra trong việc đánh giá một biểu thức (có nghĩa là, nếu kết quả không được về mặt toán học xác định hoặc không nằm trong khoảng giá trị biểu diễn cho loại hình của nó), hành vi không xác định.

Có trình chuyển mạch trình biên dịch đảm bảo các hành vi nhất định trên tràn số nguyên không? Tôi muốn tránh những con quỷ mũi. Đặc biệt, tôi muốn buộc trình biên dịch bao bọc tràn.

Vì mục đích duy nhất, hãy lấy tiêu chuẩn là C99 và trình biên dịch là gcc. Nhưng tôi sẽ quan tâm đến câu trả lời cho các trình biên dịch khác (icc, cl) và các tiêu chuẩn khác (C1x, C89). Trong thực tế, chỉ để làm phiền đám đông C/C++, tôi thậm chí sẽ đánh giá cao câu trả lời cho C++ 0x, C++ 03 và C++ 98.

Lưu ý: Tiêu chuẩn quốc tế ISO/IEC 10967-1 có thể có liên quan ở đây, nhưng theo như tôi có thể nói nó chỉ được đề cập trong phụ lục thông tin.

Trả lời

19

Hãy xem -ftrapv and -fwrapv:

-ftrapv

Tùy chọn này tạo ra cái bẫy cho tràn ký ngày hoạt động cộng, trừ, nhân.

-fwrapv

Tùy chọn này chỉ thị cho trình biên dịch cho rằng ký tràn số học cộng, trừ và nhân kết thúc tốt đẹp xung quanh sử dụng đại diện twos-bổ sung. Cờ này cho phép một số tối ưu hóa và vô hiệu hóa khác. Tùy chọn này được bật theo mặc định cho giao diện người dùng Java, theo yêu cầu của đặc tả ngôn ngữ Java.

+1

Tuyệt vời, chỉ là những gì tôi muốn xem. Có điều gì có thể so sánh được với các loại chưa ký không? – Charles

+0

@Charles bạn không cần chúng cho các loại chưa ký - hành vi tràn đã được xác định rõ cho chúng (xem câu trả lời của tôi). –

+0

@Carl Norum: Tôi thấy rằng nó được định nghĩa trong C++, và nó được định nghĩa trong C cho ca (6.5.7 para 5). Tôi không thể nhìn thấy nơi nó được xác định trong tiêu chuẩn C để bổ sung và nhân. – Charles

0

Tôi không chắc liệu có bất kỳ trình chuyển đổi trình biên dịch nào bạn có thể sử dụng để thực thi hành vi đồng nhất cho các luồng tràn trong C/C++ hay không. Một tùy chọn khác là sử dụng mẫu SafeInt<T>. Đó là một mẫu nền tảng C++ đa nền tảng cung cấp kiểm tra tràn/tràn xác định cho tất cả các loại hoạt động số nguyên.

13

Đối với câu trả lời C99 của bạn, tôi nghĩ 6,5 Expressions, đoạn 5 là những gì bạn đang tìm kiếm:

Nếu một điều kiện đặc biệt xảy ra trong đánh giá một biểu thức (có nghĩa là, nếu kết quả không được định nghĩa bằng toán học hay không trong phạm vi các giá trị có thể biểu diễn cho loại của nó), thì hành vi là không xác định.

Điều đó có nghĩa là nếu bạn bị tràn, bạn sẽ không may mắn - không có bất kỳ hành vi nào được đảm bảo. loại unsigned là một trường hợp đặc biệt, và không bao giờ tràn (6.2.5 Các loại, đoạn 9):

Một tính toán liên quan đến toán hạng unsigned không bao giờ có thể tràn, bởi vì một kết quả mà không thể được đại diện bởi các kết quả kiểu dữ liệu integer unsigned được giảm modulo số lớn hơn giá trị lớn nhất có thể được biểu thị bằng loại kết quả.

C++ có những điều khoản tương tự, diễn đạt một chút khác nhau:

  • 5 Expressions, đoạn 4:

    Nếu trong quá trình đánh giá một biểu thức, kết quả không phải là được định nghĩa bằng toán học hoặc không nằm trong phạm vi các giá trị có thể biểu diễn cho loại của nó, hành vi là không xác định. [Lưu ý: hầu hết các triển khai hiện có của C++ bỏ qua các số nguyên tràn. Điều trị phân chia bằng không, tạo thành phần còn lại bằng cách sử dụng ước số bằng không, và tất cả ngoại lệ dấu phẩy động khác nhau giữa các máy, và thường có thể điều chỉnh bằng chức năng thư viện. -endnote]

  • 3.9.1 loại cơ bản, đoạn 4:

    số nguyên Unsigned, tuyên bố unsigned, phải tuân thủ pháp luật của số học modulo 2^n nơi n là số bit trong biểu diễn giá trị của kích thước cụ thể đó của số nguyên.

+0

Vâng, đó là những gì tôi đang tìm kiếm. (Mặc dù tài liệu tham khảo nhầm lẫn với tôi lúc đầu - đó là 6,5 đoạn 5, không phải phần 6.5.5.) Bạn có biết cách nào để tránh điều này không? Gói tràn là phổ biến và có nhiều lần tôi muốn điều này xảy ra. Có bất kỳ trình biên dịch phổ biến nào có công tắc khiến chúng hứa hẹn sẽ gói gọn không? – Charles

+0

@Charles, hành vi không xác định là không xác định. Bạn có thể nhận được may mắn với trình biên dịch cụ thể của bạn - kiểm tra tài liệu của nó cho một tuyên bố rằng sẽ cung cấp cho bạn sự an tâm. Trong 'gcc', ví dụ, bạn có thể kiểm tra cờ' -fstrict-overflow' và '-fwrapv'. –

7

Trong C99 hành vi nói chung là desribed trong 6,5/5

Nếu một điều kiện đặc biệt xảy ra trong việc đánh giá một biểu thức (có nghĩa là, nếu kết quả không phải là được xác định bằng toán học hoặc không nằm trong phạm vi giá trị có thể biểu thị cho loại ), hành vi này không xác định.

Hành vi của các loại unsigned được mô tả trong 6.2.5/9, mà về cơ bản khẳng định rằng hoạt động trên các loại unsigned không bao giờ dẫn đến tình trạng đặc biệt

Một tính toán liên quan đến unsigned toán hạng có thể không bao giờ tràn, vì một kết quả không thể được đại diện bởi loại số nguyên không dấu kết quả là giảm modulo số đó là một lớn hơn giá trị lớn nhất mà có thể được biểu thị bằng kết quả là loại .

Trình biên dịch GCC có tùy chọn đặc biệt -ftrapv, được thiết kế để bắt kịp thời gian hoạt động của các số nguyên đã ký.

2

6.2.5 đoạn 9 là những gì bạn đang tìm kiếm:

Phạm vi của các giá trị không âm của một loại nguyên ký là một subrange của tương ứng kiểu unsigned integer, và các đại diện của Giá trị tương tự trong mỗi loại là giống nhau. 1) Một phép tính liên quan đến toán hạng không dấu có thể không bao giờ tràn, vì kết quả không thể được biểu diễn bằng kiểu số nguyên không kết quả là giảm modulo số lớn hơn giá trị lớn nhất có thể là được đại diện bởi ting loại.

4

Để hoàn thành, tôi muốn thêm rằng Clang hiện có "nội dung số học được kiểm tra" làm tiện ích mở rộng ngôn ngữ. Dưới đây là một ví dụ sử dụng kiểm tra nhân unsigned:

unsigned x, y, result; 
... 
if (__builtin_umul_overflow(x, y, &result)) { 
    /* overflow occured */ 
    ... 
} 
... 

http://clang.llvm.org/docs/LanguageExtensions.html#checked-arithmetic-builtins

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