Những trường hợp nào khi kiểu dữ liệu 'uint' và 'short' phù hợp hơn so với int (32) tiêu chuẩn?


24

Tôi hiểu sự khác biệt về năng lực và giá trị mà họ có thể đại diện nhưng dường như mọi người luôn sử dụng Int32bất kể nó có phù hợp hay không. Không ai từng sử dụng phiên bản không dấu ( uint) mặc dù rất nhiều thời gian nó phù hợp hơn vì nó mô tả một giá trị không thể âm (có lẽ để thể hiện ID của bản ghi cơ sở dữ liệu). Ngoài ra, dường như không ai sử dụng short/Int16bất kể dung lượng yêu cầu của giá trị.

Một cách khách quan, có trường hợp nào tốt hơn để sử dụng uinthoặc short/Int16nếu vậy, đó là những trường hợp nào?


13
Mức độ phổ biến không phải lúc nào cũng là một thước đo khả thi để đánh giá các quyết định thiết kế phần mềm. Chỉ vì một thực tiễn phổ biến không có nghĩa là đó là một thực tiễn phù hợp cho ứng dụng cụ thể của bạn hoặc thậm chí đó là một thực tiễn tốt.
Robert Harvey


1
Tôi nghĩ rằng câu trả lời ngắn gọn là các lập trình viên đã quen với ngữ nghĩa đã ký và có khuynh hướng giả định chúng, ngay cả khi xử lý các loại không dấu (và do đó là ngữ nghĩa không dấu). Hầu hết mọi người cho rằng đó là vấn đề lập trình viên lười biếng hoặc ít học, nhưng thực tế lập trình viên có thể rất có học thức và rất cẩn thận và muốn tránh những cạm bẫy tinh tế. Nếu bạn thích, hãy xem soundoftware.ac.uk/c-pitfall-uniatedanteru.net/2010/05/17/736 .
Theodoros Chatzigiannakis

Trong một số không dấu, dấu hiệu nhiều nullhơn dương hoặc âm. Nếu bạn nghĩ về nó như một thứ không bao giờ có thể tiêu cực hoặc luôn luôn tích cực, bạn sẽ ngạc nhiên (và thường tức giận) về kết quả vì nó không thực sự hoạt động theo cách đó, đặc biệt là khi so sánh với hoặc bị trừ đi / từ các giá trị đã ký.
Adam D. Ruppe

1
Theo kinh nghiệm của tôi, rất nhiều lập trình viên, những người đã từng lập trình bằng ngôn ngữ C có xu hướng quan tâm đến byte, vẫn còn trong những ngày này, về GB bộ nhớ và dung lượng lưu trữ.
dùng1451111

Câu trả lời:


25

Tôi nghi ngờ bạn đang đề cập đến một viễn cảnh được tô màu bởi những trải nghiệm của chính bạn, nơi bạn đã không làm việc xung quanh những người sử dụng các loại tích hợp đúng cách. Đây có thể là một sự xuất hiện phổ biến, nhưng đó là kinh nghiệm của tôi rằng mọi người thường sử dụng chúng một cách chính xác.

Lợi ích là không gian bộ nhớ và thời gian cpu, có thể cả không gian IO cũng tùy thuộc vào việc các loại đã từng được gửi qua dây hay vào đĩa. Các loại không được chỉ định cung cấp cho bạn kiểm tra trình biên dịch để đảm bảo bạn sẽ không thực hiện một số thao tác nhất định, cộng với việc mở rộng phạm vi khả dụng trong khi duy trì kích thước nhỏ hơn để tăng hiệu suất khi có thể cần thiết.

Việc sử dụng đúng như bạn mong đợi - bất cứ khi nào bạn biết chắc chắn bạn có thể sử dụng chúng vĩnh viễn (không ràng buộc mà không chắc chắn hoặc bạn sẽ hối hận về sau).

  • Nếu bạn đang cố gắng đại diện cho thứ gì đó không bao giờ có thể là phủ định ( public uint NumberOfPeople), hãy sử dụng loại không dấu.
  • Nếu bạn đang cố gắng đại diện cho thứ gì đó không bao giờ có thể lớn hơn 255 ( public byte DamagedToothCount), hãy sử dụng một byte.
  • Nếu bạn đang cố gắng đại diện cho thứ gì đó có thể lớn hơn 255, nhưng không bao giờ là số lượng đáng kể hàng nghìn , hãy sử dụng một đoạn ngắn ( public short JimmyHoffasBankBalance).
  • Nếu bạn đang cố gắng đại diện cho thứ gì đó có thể lên tới hàng trăm nghìn, thậm chí hàng triệu, nhưng không bao giờ đạt được nhiều tỷ, hãy sử dụng một int ( public int HoursSinceUnixEpoch).
  • Nếu bạn biết chắc chắn con số này có thể có giá trị lớn không giới hạn hoặc bạn nghĩ nó có thể có nhiều tỷ nhưng bạn không chắc chắn có bao nhiêu tỷ, bao lâu là đặt cược tốt nhất của bạn. Nếu không đủ lớn, bạn có một vấn đề thú vị và cần bắt đầu xem xét các số chính xác tùy ý ( public long MyReallyGreatAppsUserCountThisIsNotWishfulThinkingAtAll).

Lý do này có thể được sử dụng xuyên suốt trong việc lựa chọn giữa các loại kích cỡ đã ký, không dấu và đa dạng của các loại et al, chỉ cần nghĩ về các sự thật logic của dữ liệu bạn đại diện trong thực tế.


11
+1, mặc dù tôi phải nói rõ rằng số điện thoại Số điện thoại không phải là số mà là các chuỗi chữ số và định dạng tùy ý. Bạn dường như nhận thức được điều này, nhưng chúng ta không muốn làm gương xấu, bây giờ phải không? Ngoài ra, việc tự ý giới hạn phạm vi của một số giá trị là một phản mẫu thiển cận - intở mọi nơi trừ khi bạn biết rằng thực tế miền miền có vấn đề hạn chế giá trị - không ngân hàng nào muốn giới hạn tài khoản ở mức 33K (và nghĩ về niềm vui khi đó tràn ra trên đường!).
amon

3
Mục tiêu cuộc sống mới: Dự thảo quá mức có thể vượt quá loại tài khoản ngân hàng của tôi.
đệ quy.ninja

11
Có những lý do chính đáng để không sử dụng các loại không dấu ở một số nơi nhất định, ví dụ, khi số học được trộn lẫn giữa ký và không dấu. Xem các thực hành tốt nhất về ints không dấu là gì? .

19
Tôi không đồng ý với lý do ở đây. Các kiểu không được gán thường là một lỗi vì phép trừ và so sánh là bất ngờ nếu bạn đã quen với ints (chúng hoạt động theo cách nhất quán nhưng nó không "luôn luôn tích cực"). Tôi sẽ tránh chúng trừ khi bạn có một lý do rất cụ thể để sử dụng chúng. Ngoài ra, tại sao kích thước lại quan trọng đối với byte vs short vs int? Bạn thường không tiết kiệm không gian, vì các cấu trúc sẽ đưa các thành viên hoặc mảng đó vào một căn chỉnh nhất định. Tôi sẽ chỉ sử dụng một byte nếu kích thước thực sự quan trọng (đặc biệt là mã C # tôi đã thấy) hoặc nếu bạn đặc biệt muốn sử dụng mã số 255 cho một cái gì đó.
Adam D. Ruppe

4
"lợi ích là không gian bộ nhớ và thời gian cpu" ... Tôi không thấy bất kỳ trường hợp nào mà các loại nhỏ thực sự sẽ tiết kiệm thời gian CPU. Các thao tác số nguyên không bao giờ nhanh hơn các loại có kích thước máy , tức là liên quan đến CPU, bạn cũng có thể sử dụng long. Tiết kiệm bộ nhớ tất nhiên có thể gián tiếp tiết kiệm thời gian bằng cách cải thiện hiệu quả của bộ đệm và v.v., nhưng OTOH các vấn đề căn chỉnh với các loại nhỏ có thể gián tiếp tốn thời gian.
leftaroundabout

16

Chắc chắn, có những trường hợp nó tốt hơn để sử dụng uinthoặc shorthoặc Int16. Khi bạn biết rằng phạm vi dữ liệu của bạn sẽ phù hợp với các ràng buộc của loại biến đó, thì bạn có thể sử dụng loại đó.

Trong các môi trường bị hạn chế về bộ nhớ hoặc khi xử lý một lượng lớn đối tượng, việc sử dụng biến kích thước nhỏ nhất có thể có ý nghĩa. Ví dụ, có một sự khác biệt đáng kể về kích thước cho một triệu phần tử của ints so với shorts.

Thông thường, điều đó không xảy ra trong mã thực tế vì một hoặc nhiều lý do sau:

  • Hạn chế dữ liệu không được biết trước
  • Có khả năng các ràng buộc dữ liệu không vững chắc hoặc có khả năng bị thay đổi
  • Có hy vọng sử dụng lại chức năng với phạm vi dữ liệu rộng hơn
  • Nhà phát triển đã không dành thời gian để suy nghĩ về các ràng buộc
  • Tiết kiệm bộ nhớ là không đáng kể để sử dụng một loại biến nhỏ hơn

Có rất nhiều lý do có thể hơn, nhưng họ giải quyết vấn đề này: Thời gian liên quan đến việc quyết định và sử dụng một loại biến khác nhau không cung cấp đủ lợi ích để biện minh cho việc đó.


8

Trong C, trong bối cảnh không liên quan đến quảng bá số nguyên , các giá trị không dấu được chỉ định để hành xử như các thành viên của vòng đại số trừu tượng "bao bọc" (vì vậy đối với bất kỳ X và Y nào, XY sẽ mang lại một giá trị duy nhất, khi được thêm vào Y, sẽ mang lại X ), trong khi các kiểu số nguyên đã ký được chỉ định là hành vi giống như số nguyên khi các phép tính nằm trong một phạm vi nhất định và được phép làm bất cứ điều gì khi tính toán vượt quá điều đó. Tuy nhiên, ngữ nghĩa số trong C # là hoàn toàn khác nhau. Khi trong một bối cảnh số được kiểm tra, cả hai loại đã ký và không dấu đều hoạt động giống như các số nguyên được cung cấp tính toán nằm trong phạm vi và ném OverflowExceptionkhi chúng không; trong một bối cảnh không được kiểm soát, cả hai đều hành xử giống như các vòng đại số.

Lần duy nhất thường đáng để sử dụng bất kỳ loại dữ liệu nào nhỏ hơn Int32là khi cần đóng gói hoặc giải nén mọi thứ để lưu trữ hoặc vận chuyển nhỏ gọn. Nếu một người cần lưu trữ nửa tỷ số dương và tất cả chúng sẽ nằm trong phạm vi từ 0 đến 100, sử dụng mỗi byte thay vì bốn byte sẽ tiết kiệm được 1,5 gigabyte dung lượng lưu trữ. Đó là một khoản tiết kiệm lớn. Tuy nhiên, nếu một đoạn mã cần lưu trữ tổng cộng vài trăm giá trị, tuy nhiên, làm cho mỗi mã một byte thay vì bốn sẽ tiết kiệm khoảng 600 byte. Có lẽ không đáng bận tâm.

Đối với các loại không dấu, lần duy nhất chúng thực sự hữu ích là khi thực hiện trao đổi thông tin hoặc khi chia số thành các phần. Ví dụ, nếu người ta cần làm toán trên các số nguyên 96 bit, thì việc thực hiện các phép tính trên các nhóm ba số nguyên 32 bit không dấu sẽ dễ dàng hơn nhiều so với các nhóm số nguyên đã ký. Mặt khác, không có nhiều tình huống trong đó phạm vi của giá trị 32 hoặc 64 bit đã ký sẽ không đủ, nhưng cùng một kích thước của giá trị không dấu sẽ đủ.


4

Nói chung là một ý tưởng tồi để sử dụng các loại không dấu vì chúng tràn theo những cách khó chịu. x = 5-6đột nhiên là một khung thời gian trong mã của bạn. Trong khi đó, lợi ích của các loại không dấu sẽ tăng thêm một chút độ chính xác và nếu bit đó có giá trị với bạn, bạn gần như chắc chắn nên sử dụng loại lớn hơn thay thế.

Có những trường hợp sử dụng trong đó một loại nhỏ hơn có thể có ý nghĩa nhưng trừ khi bạn lo lắng về việc sử dụng bộ nhớ hoặc cần đóng gói dữ liệu để truyền hoặc hiệu quả bộ đệm hoặc một số mối quan tâm khác, thông thường không có lợi cho việc sử dụng loại nhỏ hơn . Hơn nữa, trên nhiều kiến ​​trúc, việc sử dụng các loại này thực sự chậm hơn để chúng thực sự có thể áp đặt một chi phí nhỏ.


3
Trong C, tràn đã ký thậm chí còn tồi tệ hơn tràn không dấu (vì đó là hành vi không xác định, trong khi không dấu được chỉ định để cuộn giống như một máy đo đường). OTOH, ký hiệu vượt / ký kết ít phổ biến hơn nhiều trong thực tế so với dòng không dấu.
Kevin

Đúng, nhưng tràn đã ký thường rõ ràng hơn và có thể dự đoán.
Jack Aidley

Tôi thường đồng ý, nhưng bạn cần lưu ý, ví dụ, các trình biên dịch hiện đại có thể tối ưu hóa i+1>ithành 1nếu iđược ký kết, cùng với một loạt các hành vi khó chịu khác. Tràn không được ký có thể gây ra lỗi trong trường hợp góc. Ký tràn có thể làm cho toàn bộ chương trình của bạn trở nên vô nghĩa .
Kevin

@JackAidley Tôi khá chắc chắn những gì bạn nói không có ý nghĩa gì, vì 5-6 mang lại mô hình bit giống nhau, bất kể nó có dấu hay không.
Ingo

@Ingo: bạn có thường xuyên nhìn vào các mẫu bit không? Điều quan trọng là ý nghĩa của mẫu bit không phải là bit nào được bật hay tắt.
Jack Aidley

2

Thường bị lãng quên và có thể tiếp tuyến với câu hỏi của bạn, khi giao dịch cụ thể với các loại .NET, là Tuân thủ CLS . Không phải tất cả các loại đều có sẵn cho tất cả các ngôn ngữ được xây dựng trên .NET Framework.

Nếu bạn đang viết mã được sử dụng bởi các ngôn ngữ khác ngoài C # và muốn mã đó được đảm bảo để tương tác với càng nhiều ngôn ngữ .NET càng tốt thì bạn phải hạn chế sử dụng loại của mình đối với các ngôn ngữ tuân thủ CLS.

Ví dụ: các phiên bản ban đầu của VB.NET (7.0 và 7.1) không hỗ trợ các số nguyên không dấu ( UInteger):

http://msdn.microsoft.com/en-us/l Library / aa903459 (v = vs.71) .aspx

Các số nguyên không được gán không tuân thủ CLS và do đó nên được sử dụng cẩn thận nếu bạn không chắc chắn ai sẽ là người tiêu dùng thư viện lớp của bạn.

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 cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.