2011-02-02 45 views
25

Trong câu hỏi này chủ đề là làm thế nào để làm cho VS séc cho một tràn số học trong C# và ném một ngoại lệ: C# Overflow not Working? How to enable Overflow Checking?Tại sao bạn muốn tràn số nguyên xảy ra?

Một trong những ý kiến ​​phát biểu điều gì đó kỳ lạ và đã bỏ phiếu tán nhiều, tôi hy vọng bạn có thể giúp tôi ra ở đây:

Bạn cũng có thể sử dụng từ khóa đã chọn để bọc một câu lệnh hoặc một bộ câu lệnh để chúng được kiểm tra rõ ràng về tràn số học. Việc thiết lập thuộc tính toàn dự án là một chút rủi ro vì thỉnh thoảng tràn là một kỳ vọng khá hợp lý.

Tôi không biết nhiều về phần cứng nhưng tôi biết rằng tràn phải thực hiện với cách đăng ký hoạt động. Tôi luôn luôn nghĩ rằng tràn gây ra hành vi không xác định và nên được ngăn chặn nếu có thể. (trong các dự án 'bình thường', không viết mã độc hại)

Tại sao bạn lại bao giờ mong đợi một sự cố xảy ra và tại sao bạn không luôn ngăn chặn nó nếu bạn có khả năng? (bằng cách đặt tùy chọn trình biên dịch tương ứng)

+0

(tham khảo) http://en.wikipedia.org/wiki/Integer_overflow –

+1

Câu lệnh của bạn "tràn gây ra hành vi không xác định" là không chính xác ... nó được xác định rất tốt, đặc biệt là trong trường hợp số nguyên. Tuyên bố của bạn "Tôi không biết nhiều về phần cứng" đang nói trong trường hợp này ... bạn nên đọc một chút về nhị phân và cách bổ sung hoạt động ở mức máy – JoelFan

+1

Câu lệnh có thể xuất phát từ tư duy C/C++, tràn là một "hành vi không xác định" có nghĩa là người biên dịch trình biên dịch có thể làm những việc bạn không mong đợi khi tối ưu hóa. Nó không thực sự quan trọng mà CPU có một hành vi được xác định rõ ràng, trình biên dịch với biểu thức hằng số bignum đánh giá optimiser, có thể phát hiện và loại bỏ mã "nó không phải là chương trình C/C++ để tôi có thể phá vỡ nó". Tôi đoán, không ai cần quan tâm đến C#, bởi vì thời gian phần cứng mới làm việc khác, MS đã chuyển sang một số đạn bạc mới – Rob11311

Trả lời

35

Thời gian chính khi tôi muốn tràn được tính mã băm. Ở đó, độ lớn số thực tế của kết quả không quan trọng chút nào - nó chỉ là một mẫu mà tôi tình cờ thao tác với các phép toán số học.

Chúng tôi đã kiểm tra số học được bật trên toàn dự án cho Noda Time - Tôi muốn ném ngoại lệ hơn là trả lại dữ liệu không chính xác. Tôi nghi ngờ rằng nó là khá hiếm hoi cho tràn được mong muốn ... Tôi sẽ thừa nhận tôi thường là để mặc định cho số học không được kiểm tra, chỉ vì nó là mặc định. Có hình phạt tốc độ là tốt, tất nhiên ...

+10

Độ chính xác và tốc độ của bạn thực sự gây phiền nhiễu. Chúc mừng! –

3

tại sao bạn không luôn ngăn chặn nó nếu bạn có khả năng?

Lý do được kiểm tra số học không được bật theo mặc định là số học được kiểm tra chậm hơn so với số học không được kiểm tra. Nếu hiệu suất không phải là một vấn đề cho bạn nó có lẽ sẽ có ý nghĩa để cho phép số học kiểm tra như một tràn xảy ra thường là một lỗi.

+0

Ok, tôi không biết điều đó và nó có vẻ hợp lý. Điều đó vẫn không giải thích tại sao bình luận nói rằng "tràn bộ nhớ là một kỳ vọng khá hợp lý"? Nhìn vào mức độ thường xuyên nó được upvoted (+10 trong 2 giờ) anh ta dường như không phải là người duy nhất có ý kiến ​​này? – magnattic

+2

Sự khác biệt chủ yếu là số học đã ký. Vì cách thức bù đắp của số 2 làm việc, nên 11111111 8 bit thực sự là âm 1 thay vì sByte.MinValue -128 (như bạn có thể đã mong đợi). Nó có ý nghĩa mặc dù; thêm 1 đến -1 sẽ cho kết quả bằng không, do đó, thêm 00000001 đến 11111111 == 00000000. Đó là tràn số học về mặt kỹ thuật; các bit mang 1 của đầu bên trái của byte không có bất cứ nơi nào để đi trong byte được phân bổ, và như vậy là bị mất. Tuy nhiên, các số nguyên luôn đi giữa tích cực và tiêu cực mọi lúc, do đó, đây chỉ là lỗi khi bạn muốn. – KeithS

1

Có một câu chuyện kinh điển về một lập trình viên đã tận dụng tràn trong việc thiết kế một chương trình:

The Story of Mel

+1

Đây là câu trả lời hữu ích như thế nào? – BoltClock

+0

Trong khi một câu chuyện thú vị (có thể là một huyền thoại đô thị lập trình) không ai nên làm bất cứ điều gì như thế những ngày này trừ khi bạn đang làm việc tại phần vững hoặc một cái gì đó siêu cấp thấp. Hầu hết chắc chắn không phải trong C# – Davy8

+3

Nên là một bình luận, nếu có. –

3

Khi tạo mã băm, nói từ một chuỗi ký tự.

0

Một tình huống có thể xảy ra nữa mà tôi có thể chụp là ngẫu nhiên tạo số ngẫu nhiên - chúng tôi không đề cập đến tình trạng tràn trong trường hợp đó, bởi vì tất cả những gì chúng tôi muốn là một số ngẫu nhiên.

1

Điều này không liên quan nhiều đến cách sổ đăng ký hoạt động vì nó chỉ là giới hạn của bộ nhớ trong các biến lưu trữ dữ liệu. (Bạn có thể tràn một biến trong bộ nhớ mà không làm tràn bất kỳ thanh ghi nào.)

Nhưng để trả lời câu hỏi của bạn, hãy xem xét loại kiểm tra đơn giản nhất. Nó chỉ đơn giản là tổng của tất cả các dữ liệu được kiểm tra. Nếu kiểm tra tràn, thì không sao và phần không tràn vẫn còn có ý nghĩa.

Các lý do khác có thể bao gồm việc bạn chỉ muốn chương trình của mình tiếp tục chạy mặc dù biến không quan trọng có thể đã tràn.

+0

CPU không thực hiện bất kỳ công việc nào trên bộ nhớ, chúng hoạt động trên thanh ghi. Đăng ký được sao chép vào bộ nhớ khi nó được thực hiện đang được làm việc trên. Vì vậy, nó thực sự là về cách đăng ký tràn. – Bengie

+0

Bạn đã nhận thông tin của mình từ đâu về CPU không bao giờ làm việc trực tiếp với bộ nhớ? Đâu là đăng ký tràn trong một tuyên bố như 'ADD MyVar, 1' hoặc thậm chí' ADD [esi], 1'? CPU chắc chắn hoạt động trực tiếp trên bộ nhớ. –

10

Tôi luôn nghĩ nguyên nhân tràn gây ra hành vi chưa xác định và phải là được ngăn chặn nếu có thể.

Bạn cũng có thể nhầm lẫn về sự khác biệt giữa tràn bộ đệm (tràn) và tràn số.

Lỗi tràn bộ đệm là khi dữ liệu được ghi qua phần cuối của mảng không được quản lý. Nó có thể gây ra hành vi không xác định, làm những việc như ghi đè địa chỉ trả về trên ngăn xếp với dữ liệu do người dùng nhập. Lỗi tràn bộ đệm rất khó thực hiện trong mã được quản lý.

Luồng số, tuy nhiên, được xác định rõ. Ví dụ, nếu bạn có một thanh ghi 8 bit, nó chỉ có thể lưu trữ 2^8 giá trị (0 đến 255 nếu không dấu). Vì vậy, nếu bạn thêm 100 + 200, bạn sẽ không nhận được 300, nhưng 300 modulo 256, là 44. Câu chuyện phức tạp hơn một chút khi sử dụng các loại đã ký; mẫu bit được tăng lên theo cách tương tự, nhưng chúng được hiểu là two's complement, vì vậy việc thêm hai số dương có thể cho số âm.

+0

+1 cho giải thích tuyệt vời đó. Tôi biết sự khác biệt giữa bộ đệm và tràn số học, nhưng vẫn nghĩ rằng đó là (ít nhất là trong lý thuyết) hành vi không xác định trong mọi trường hợp. – magnattic

+0

Bạn có biết ai đã xác định rõ luồng không? Nó là phần cứng? Nó có phải là nền tảng (.NET, Java, v.v.) không? Hãy tưởng tượng bạn muốn viết mã băm số nguyên (xây dựng bỏ qua các luồng) cả từ chương trình .NET trên máy 32 bit và từ một chương trình Java trên máy 64 bit. Giả sử tất cả các số nguyên có cùng kích thước, các hashcodes có ý nghĩa tương đương không? –

+1

@Marco - Trong hầu hết các trường hợp, tràn số nguyên sẽ được xác định rõ ở mọi cấp độ, trên thực tế. Ví dụ: [C#] (http://en.csharp-online.net/ECMA-334:_14.7.4_Addition_operator): "bất kỳ bit có thứ tự cao đáng kể nào nằm ngoài phạm vi của loại kết quả sẽ bị loại bỏ", [Java] (http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html): "Nếu một tràn bổ sung nguyên, thì kết quả là các bit bậc thấp của tổng toán học như được biểu diễn trong một số định dạng bổ sung đủ lớn hai ". – Justin

3

Điều này có thể có liên quan nhiều đến lịch sử như với bất kỳ lý do kỹ thuật nào. Sự tràn số nguyên đã rất thường được sử dụng để có hiệu quả tốt bởi các thuật toán dựa vào hành vi (các thuật toán băm đặc biệt).

Ngoài ra, hầu hết các CPU được thiết kế để cho phép tràn, nhưng thiết lập một bit mang theo trong quá trình, giúp dễ dàng thực hiện bổ sung trên các kích thước từ dài hơn tự nhiên. Để thực hiện các hoạt động được kiểm tra trong ngữ cảnh này có nghĩa là thêm mã để tăng ngoại lệ nếu cờ thực hiện được đặt. Không phải là một áp đặt rất lớn, nhưng một trong những nhà biên dịch trình biên dịch có lẽ không muốn foist khi mọi người mà không có sự lựa chọn.

Cách thay thế sẽ là kiểm tra theo mặc định, nhưng cung cấp tùy chọn không được chọn. Tại sao điều này không phải như vậy cũng có thể quay trở lại lịch sử.

2

Bạn có thể mong đợi nó trên một cái gì đó được đo cho đồng bằng. Một số thiết bị mạng giữ kích thước truy cập nhỏ và bạn có thể thăm dò ý kiến ​​cho một giá trị, nói rằng byte được chuyển. Nếu giá trị quá lớn, nó sẽ tràn về 0. Nó vẫn cung cấp cho bạn một cái gì đó hữu ích nếu bạn đang đo nó thường xuyên (byte/phút, byte/giờ), và như các quầy thường được xóa khi kết nối giảm nó không quan trọng họ không hoàn toàn chính xác.

Khi Justin đề cập đến tràn bộ đệm là một ấm khác nhau của cá. Đây là nơi bạn viết qua phần cuối của một mảng vào bộ nhớ mà bạn không nên. Trong tràn số, cùng một lượng bộ nhớ được sử dụng. Trong tràn bộ đệm, bạn sử dụng bộ nhớ mà bạn không phân bổ. Tràn bộ đệm được ngăn chặn tự động trong một số ngôn ngữ.

9

Khi thực hiện các phép tính với các bộ đếm gia tăng liên tục. Ví dụ cổ điển là Environment.TickCount:

int start = Environment.TickCount; 
DoSomething(); 
int end = Environment.TickCount; 
int executionTime = end - start; 

Nếu được chọn, chương trình có tỷ lệ cược sau 27 ngày kể từ khi Windows khởi động. Khi TickCount đánh dấu vượt quá int.MaxValue trong khi DoSomething đang chạy. PerformanceCounter là một ví dụ khác.

Các loại tính toán này tạo ra kết quả chính xác, ngay cả khi có tràn. Ví dụ thứ hai là loại toán bạn làm để tạo ra một mẫu bit đại diện, bạn không thực sự quan tâm đến kết quả chính xác, chỉ là một kết quả có thể lặp lại được. Ví dụ về những người đó là tổng kiểm tra, băm và số ngẫu nhiên.

+1

Trong trường hợp đó, một ngoại lệ có thể tốt hơn nhiều so với phần dưới - thường hủy bỏ tốt hơn là tạo ra dữ liệu không chính xác mà sau đó có thể xếp tầng xuyên qua hệ thống. Phụ thuộc vào tình hình, tất nhiên. –

+5

@ Jon - tuyệt đối không, tính toán là chính xác. –

+0

trừ khi nó tràn nhiều lần. :) – darron

0

Lỗi tràn số nguyên như sau.

Bạn có số nguyên 8 bit 1111 1111, hiện thêm 1 vào số đó. 0000 0000, hàng đầu 1 bị cắt bớt vì nó sẽ ở vị trí thứ 9.

Bây giờ, bạn có số nguyên đã ký, bit hàng đầu có nghĩa là số âm. Vì vậy, bây giờ bạn có 0111 1111. Thêm 1 vào nó và bạn có 1000 0000, là -128. Trong trường hợp này, việc thêm 1 đến 127 làm cho nó chuyển thành âm.

Tôi rất chắc chắn các hành vi tràn hoạt động theo cách được xác định rõ ràng, nhưng tôi không chắc chắn về các luồng nhỏ.

0

Tất cả số học số nguyên (cũng cộng các phép trừ và nhân ít nhất) là chính xác. Nó chỉ là việc giải thích các bit kết quả mà bạn cần phải cẩn thận. Trong hệ thống bổ sung của 2, bạn có được kết quả chính xác modulo 2 đến số bit. Sự khác biệt duy nhất giữa chữ ký, và unsigned là đối với các số đã ký, bit quan trọng nhất được coi là bit dấu. Của nó lên đến các lập trình viên để xác định những gì là thích hợp. Rõ ràng đối với một số tính toán bạn muốn biết về tràn và thực hiện hành động thích hợp nếu phát hiện thấy một. Cá nhân tôi chưa bao giờ cần phát hiện tràn. Tôi sử dụng một bộ tạo số ngẫu nhiên tuyến tính dựa trên nó, tức là 64 * 64bit phép nhân số nguyên không dấu, tôi chỉ quan tâm đến 64 bit thấp nhất, tôi nhận được phép toán modulo miễn phí vì cắt ngắn.

5

Angles

Số nguyên mà tràn là những công cụ thanh lịch để đo góc. Bạn có 0 == 0 độ, 0xFFFFFFFF == 359,999 .... độ. Rất thuận tiện của nó, bởi vì như số nguyên 32 bit bạn có thể thêm/trừ góc (350 độ cộng với 20 độ kết thúc lên tràn gói trở lại khoảng 10 độ). Ngoài ra, bạn có thể quyết định xử lý số nguyên 32 bit như đã ký (-180 đến 180 độ) và chưa ký (0 đến 360). 0xFFFFFFF tương đương với -179.999 ..., tương đương với 359.999 ..., tương đương nhau. Rất sang trọng.

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