sử dụng uint so với int [đã đóng]


83

Tôi đã quan sát thấy một thời gian rằng các lập trình viên C # có xu hướng sử dụng int ở khắp mọi nơi, và hiếm khi sử dụng uint. Nhưng tôi chưa bao giờ tìm ra câu trả lời thỏa đáng là tại sao.

Nếu mục tiêu của bạn là khả năng tương tác, uint sẽ không xuất hiện trong các API công khai vì không phải tất cả các ngôn ngữ CLI đều hỗ trợ số nguyên không dấu. Nhưng điều đó không giải thích tại sao int lại phổ biến như vậy, ngay cả trong các lớp nội bộ. Tôi nghi ngờ đây là lý do uint được sử dụng ít trong BCL.

Trong C ++, nếu bạn có một số nguyên mà giá trị âm không có nghĩa, bạn chọn một số nguyên không dấu.

Điều này rõ ràng cho thấy rằng các số âm không được phép hoặc được mong đợi và trình biên dịch sẽ thực hiện một số kiểm tra cho bạn. Tôi cũng nghi ngờ trong trường hợp chỉ số mảng, JIT có thể dễ dàng bỏ kiểm tra giới hạn thấp hơn.

Tuy nhiên, khi trộn kiểu int và đơn vị, sẽ cần thêm cẩn thận và phôi.

Có nên sử dụng uint nhiều hơn không? Tại sao?



Chỉ cần tôi đã có một deja vu: D, gần chính xác câu hỏi đã được hỏi cách đây không lâu.
— KroaX

Đối với séc giới hạn thấp hơn (trong trường hợp bạn cần phải viết của riêng bạn), bạn có thể thay thế if (i < 0 || i >= length)bằng if (unchecked((uint)i) >= length). Kết quả IL sẽ có tổng số lệnh ít hơn một (nhánh) và sẽ cho hiệu suất xấp xỉ như nhau (nhanh hơn một cách nhanh chóng). Cá nhân tôi yêu nó đơn giản vì nó làm trầy xước chỗ ngứa của tôi khi kiểm tra các giới hạn thấp hơn. Những người khác có thể tranh luận chống lại nó do "không được kiểm tra", nhưng tôi cho rằng đây là một dòng rất tốt để tìm hiểu ý nghĩa của nó vì nó đơn giản và rõ ràng ngay lập tức từ ngữ cảnh mục đích là gì = giúp người đọc tìm hiểu.
— AnorZaken

Quên đề cập rằng ở trên là tối ưu trên các bản dựng 64 bit vì nó sẽ thực hiện so sánh với 64 bit. Đối với các bản dựng 32bit if (unchecked((uint)i) >= unchecked((uint)length))cho hiệu suất tốt hơn. Tuy nhiên, điều này trông rất phức tạp và so sánh 64 bit vẫn hoạt động hiệu quả hơn so với kiểm tra giới hạn phân nhánh kép tiêu chuẩn trên bản dựng 32 bit, vì vậy tôi thực sự không thể đề xuất điều này trong bất kỳ tình huống hợp lý nào. (Tôi chủ yếu đề cập đến nó chỉ ra rằng 64-bit so sánh được sử dụng bằng cách khác -. Mà có thể là thông tin hữu ích cho một số)
— AnorZaken

Các quý ông, tôi cho rằng cơ sở quan điểm chính của các ông là không tốt. Nếu có một câu trả lời khách quan có thể, tôi vì một người, rất muốn nghe nó. Tôi là tất cả để thay đổi thực hành của tôi vì lợi ích.
— Joshua,

Câu trả lời:


50

Quan sát của bạn về lý do uintTôi nghi ngờ rằng không được sử dụng trong BCL là lý do chính.

UInt32 không tuân thủ CLS, có nghĩa là nó hoàn toàn không phù hợp để sử dụng trong các API công khai. Nếu bạn đang sử dụng uint trong API riêng tư của mình, điều này có nghĩa là thực hiện chuyển đổi sang các loại khác - và thường dễ dàng hơn và an toàn hơn nếu chỉ giữ nguyên loại.

Tôi cũng nghi ngờ rằng điều này không phổ biến trong quá trình phát triển C #, ngay cả khi C # là ngôn ngữ duy nhất đang được sử dụng, chủ yếu vì nó không phổ biến trong BCL. Nói chung, các nhà phát triển cố gắng (rất may) bắt chước phong cách của khuôn khổ mà họ đang xây dựng - trong trường hợp của C #, điều này có nghĩa là cố gắng làm cho các API của bạn, công khai và nội bộ, giống với .NET Framework BCL nhất có thể. Điều này có nghĩa là sử dụng uint một cách tiết kiệm.


1
stackoverflow.com/questions/2013116/... là một câu hỏi mà giao dịch với một chủ đề tương tự
— Stephan

77

intngắn hơn để gõ hơn uint.


2
Tôi nghi ngờ điều này khá gần với sự thật. Tại sao lại sử dụng uintkhi 99% thời gian (theo kinh nghiệm của tôi) là intđủ?
— Matthew Jones

12
@Justin: "Những con số kỳ diệu" như -1 không phải là một ý kiến ​​hay, nói chung. Chuyển sang long có nghĩa là sử dụng bộ nhớ gấp đôi mà không có lý do gì cả, ... "đơn vị" chắc chắn có giá trị, miễn là bạn không cần phải tương tác với các API khác.
— Reed Copsey

28
Tôi không bao giờ cảm thấy thoải mái khi sử dụng một intđể lập chỉ mục một mảng, bởi vì tôi sẽ không bao giờ có một chỉ mục âm. Có vẻ rõ ràng một cách mù quáng rằng a uintnên được sử dụng trong trường hợp này.
— Mark H

2
Chưa kể, dễ đọc hơn. Nếu bạn từng chuyển mã / thuật toán của mình cho người khác đọc mà có thể ít kinh nghiệm hơn bạn, việc sử dụng nhiều mã uintcó thể khiến chúng bị treo một chút. inthoàn toàn có thể chấp nhận được để sử dụng trong mọi tình huống mà bạn kiểm soát phạm vi hoạt động của nó.
— drharris

3
@MarkH Hoàn toàn đồng ý, nhưng khi thực hiện một sự lặp lại ngược lại nó có thể hữu ích trong các hình thức: for (int i = arr.Length - 1; i >= 0; i--) { }. Làm điều đó với một uint sẽ dẫn đến một ngoại lệ tràn hoặc tệ hơn, một vòng lặp vô hạn.
— Aidiakapi

19

Bình thường intsẽ đủ. Nếu bạn có thể đáp ứng tất cả các điều kiện sau, bạn có thể sử dụng uint:

  • Nó không dành cho một API công khai (vì uint không tuân thủ CLS).
  • Bạn không cần số âm.
  • Bạn (có thể) cần phạm vi bổ sung.
  • Bạn không sử dụng nó để so sánh với < 0, vì điều đó không bao giờtrue.
  • Bạn không sử dụng nó để so sánh với >= 0, vì điều đó là không bao giờ false.

Yêu cầu cuối cùng thường bị quên và sẽ đưa ra các lỗi:

static void Main(string[] args)
{
    if (args.Length == 0) return;
    uint last = (uint)(args.Length - 1);

    // This will eventually throw an IndexOutOfRangeException:
    for (uint i = last; i >= 0; i--)
    {
        Console.WriteLine(args[i]);
    }
}

13

1) Thói quen xấu. Nghiêm túc. Ngay cả trong C / C ++.

Hãy nghĩ về formô hình chung :

for( int i=0; i<3; i++ )
    foo(i);

Hoàn toàn không có lý do gì để sử dụng một số nguyên ở đó. Bạn sẽ không bao giờ có giá trị âm. Nhưng hầu như tất cả mọi người sẽ thực hiện một vòng lặp đơn giản theo cách đó, ngay cả khi nó chứa (ít nhất) hai lỗi "style" khác.

2) intđược coi là kiểu gốc của máy.


4

Tôi thích uintđể inttrừ một số âm là thực sự trong khoảng giá trị có thể chấp nhận. Đặc biệt, việc chấp nhận một inttham số nhưng ném một ArgumentExceptiontham số nếu số nhỏ hơn 0 chỉ là ngớ ngẩn - hãy sử dụng a uint!

Tôi đồng ý rằng nó uintđang được sử dụng ít và tôi khuyến khích mọi người sử dụng nó nhiều hơn.


7
Rất nguy hiểm nếu chỉ chấp nhận các uints và không kiểm tra các giới hạn. Nếu ai đó chuyển một giá trị âm, CLR sẽ giải thích nó là một số nguyên lớn, nghĩa là với -1 bạn nhận được giá trị uint.max. Đây không phải là hành vi mong muốn.
— Henri

19
@Henri: C # không có chuyển đổi ngầm định từ int sang uint, vì vậy không có "Nếu ai đó chuyển giá trị âm". Tất nhiên kiểm tra giới hạn trên giới hạn trên vẫn thích hợp (nhưng bây giờ bạn chỉ cần một séc thay vì hai).
— Ben Voigt

1

Tôi lập trình ở lớp ứng dụng cấp thấp hơn, nơi int hiếm khi vượt quá 100, vì vậy giá trị âm không phải là vấn đề (ví dụ: đối với thứ i <myname.length () type) nó chỉ là một thói quen cũ của C - và ngắn hơn để nhập như đã đề cập ở trên. Tuy nhiên, trong một số trường hợp, khi giao tiếp với phần cứng mà tôi đang xử lý cờ sự kiện từ các thiết bị, uint rất quan trọng trong trường hợp cờ có thể sử dụng bit bên trái (cao nhất) nhiều nhất.

Thành thật mà nói, đối với 99,9% công việc của tôi, tôi có thể dễ dàng sử dụng ushort, nhưng int, bạn biết đấy, nghe có vẻ tốt hơn rất nhiều so với ushort.


1

Tôi đã tạo một trình bao bọc Direct3D 10 trong C # và cần sử dụng uint nếu tôi muốn tạo các bộ đệm đỉnh rất lớn. Bộ đệm lớn trong thẻ video không thể được biểu diễn bằng một int đã ký.

UINT rất hữu ích và thật ngớ ngẩn khi nói khác đi. Nếu ai đó nghĩ rằng chỉ vì họ chưa bao giờ cần sử dụng uint mà không ai khác sẽ làm thì bạn đã nhầm.


Đó là một trường hợp tốt mà bạn có thể tận dụng lợi thế của phạm vi rộng hơn.
— Leo Gurdian

0

Tôi nghĩ đó chỉ là sự lười biếng. C # vốn dĩ là một lựa chọn để phát triển trên máy tính để bàn và các máy khác có tương đối nhiều tài nguyên.

Tuy nhiên, C và C ++ có nguồn gốc sâu xa từ các hệ thống cũ và hệ thống nhúng, nơi bộ nhớ thưa thớt, vì vậy các lập trình viên thường phải suy nghĩ cẩn thận về loại dữ liệu nào sẽ sử dụng. Các lập trình viên C # rất lười biếng và vì có đủ tài nguyên nói chung nên không ai thực sự tối ưu hóa việc sử dụng bộ nhớ (tất nhiên là không phải lúc nào cũng vậy). Sự kiện nếu một byte sẽ là đủ, rất nhiều lập trình viên C #, bao gồm cả tôi, chỉ sử dụng int cho đơn giản. Hơn nữa, rất nhiều hàm API chấp nhận int, vì vậy nó ngăn chặn quá trình truyền.

Tôi đồng ý rằng việc chọn đúng kiểu dữ liệu là một cách làm tốt, nhưng tôi nghĩ động lực chính là sự lười biếng.

Cuối cùng, việc chọn một số nguyên chính xác hơn về mặt toán học. Các int không dấu không tồn tại trong toán học (chỉ số tự nhiên). Và vì hầu hết các lập trình viên đều có nền tảng toán học nên việc sử dụng một số nguyên sẽ tự nhiên hơn.


Tôi sẽ không nói đó là sự lười biếng, mặc dù sự lười biếng có giá trị của nó. Hơn nữa, hầu hết thời gian, tôi không quan tâm đủ đến thứ int / uint, để lãng phí chu kỳ não của mình cho một quyết định như vậy, và chỉ đi với int. Phần cứng rất đắt, lập trình viên có thể tốn kém.
— SWeko

Lập trình viên lười biếng. Đó là một điều tồi tệ. Raymond sẽ nói rằng các lập trình viên ghét phải trả thuế của họ!
— lornova

Tôi sẽ là người đầu tiên quản trị rằng các lập trình viên C # của chúng tôi rất lười biếng nhưng đó không hẳn là một điều xấu.
— ChaosPandion

@Lorenzo, tôi đã viết một bài báo ở trường đại học, nói rằng một lập trình viên lười biếng là một lập trình viên giỏi. Chủ yếu là tối ưu hóa thời gian của lập trình viên thay vì thời gian của máy móc.
— Eloff

1
Hmm, hầu hết các lỗi lập trình viên-imputable mà tôi từng thấy (hoặc thực hiện) là do sự lười biếng ...
— lornova

0

Tôi nghĩ một phần lớn lý do là khi C lần đầu tiên xuất hiện hầu hết các ví dụ được sử dụng intvì mục đích ngắn gọn. Chúng tôi rất vui vì không phải viết integernhư chúng tôi đã làm với Fortran và Pascal, và trong những ngày đó, chúng tôi thường sử dụng chúng cho những thứ thông thường như chỉ số mảng và bộ đếm vòng lặp. Số nguyên không dấu là trường hợp đặc biệt đối với các số lớn cần thêm bit cuối cùng. Tôi nghĩ rằng đó là một tiến trình tự nhiên mà thói quen C tiếp tục sang C # và các ngôn ngữ mới khác như Python.


0

Một số ngôn ngữ (ví dụ nhiều phiên bản của Pascal) coi các kiểu không dấu là đại lượng số; một phép toán giữa kiểu không dấu và kiểu có dấu có cùng kích thước nói chung sẽ được thực hiện như thể các toán hạng đã được thăng cấp thành kiểu lớn hơn tiếp theo (trong một số ngôn ngữ như vậy, kiểu lớn nhất không có dấu tương đương, vì vậy việc thăng hạng như vậy sẽ luôn khả thi ).

Các ngôn ngữ khác (ví dụ C) coi các kiểu không dấu N-bit là một nhóm bao bọc xung quanh mô-đun 2 ^ N. Lưu ý rằng việc trừ N khỏi một thành viên của một nhóm như vậy không đại diện cho phép trừ số, mà mang lại thành viên nhóm mà khi N được thêm vào nó, sẽ mang lại kết quả ban đầu. Có thể cho rằng, một số hoạt động liên quan đến hỗn hợp các giá trị có dấu và không dấu không thực sự có ý nghĩa và lẽ ra phải bị cấm, nhưng ngay cả mã cẩu thả với các thông số kỹ thuật của nó như các ký tự số cũng thường hoạt động và mã đã được viết để trộn các giá trị có dấu và các loại không dấu và, mặc dù cẩu thả, nhưng hoạt động, mà thông số kỹ thuật không có khả năng thay đổi sớm.

Làm việc độc quyền với các loại đã ký sẽ dễ dàng hơn rất nhiều so với việc tìm ra tất cả các tương tác phức tạp giữa các loại đã ký và chưa ký. Các loại không có dấu rất hữu ích khi phân tách các số lớn thành các phần nhỏ hơn (ví dụ: để tuần tự hóa) hoặc để tạo lại các số như vậy, nhưng nói chung tốt hơn là chỉ sử dụng các số có dấu cho những thứ thực sự đại diện cho số lượng


0

Tôi biết đây có thể là một chủ đề cũ nhưng tôi muốn đưa ra một số làm rõ.

Cho phép lấy một int8, bạn có thể lưu trữ –128 đến 127 và nó sử dụng 1 byte có tổng số 127 số dương.
Khi bạn sử dụng int8, một trong các bit được sử dụng cho các số âm -128.
Khi bạn sử dụng Uint8, bạn cung cấp các số âm cho số dương để điều này cho phép bạn sử dụng 255 số dương với cùng một lượng lưu trữ 1 byte.
Điểm trở lại duy nhất là bạn đã mất khả năng sử dụng các giá trị âm.
Một vấn đề khác với điều này là không phải tất cả các ngôn ngữ lập trình và cơ sở dữ liệu đều hỗ trợ điều này.
Lý do duy nhất bạn nên sử dụng điều này theo ý kiến ​​của tôi là khi bạn cần phải hiệu quả như lập trình trò chơi và bạn phải lưu trữ số lượng lớn không âm. Đây là lý do tại sao không nhiều chương trình sử dụng nó.

Lý do chính là lưu trữ không phải là một vấn đề và bạn không thể sử dụng nó một cách linh hoạt với phần mềm, plugin, Cơ sở dữ liệu hoặc Api's khác. Ngoài ra, ví dụ một ngân hàng sẽ cần số âm để lưu trữ tiền, v.v.

Tôi hy vọng điều này sẽ giúp một ai đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookie và Chính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.