Là số nguyên được sử dụng quá nhiều như một loại dữ liệu?


9

Có phải hầu hết các nhà phát triển ứng dụng sử dụng số nguyên đã ký ở những nơi họ thực sự muốn sử dụng số nguyên không dấu? Tôi làm điều đó mọi lúc, đồng nghiệp của tôi cũng vậy. Tôi đã không thấy nhiều cơ sở mã hóa rộng lớn khác (trừ Delphi VCL) và các ví dụ trên internet thường sử dụng số nguyên. Trong khi đó, các nhà phát triển VCL sử dụng các kiểu dữ liệu của riêng họ (đó sẽ là cách không lười biếng nhất để khai báo các biến).

Một cái gì đó có vẻ hơi đáng sợ về mã như thế này

TStuffRec = record
   recordID : Integer;
   thingID : Integer;
   otherThingID : Integer;
end;

khi nó có thể được viết là

TStuffRec = record
   recordID : Cardinal;
   thingID : Cardinal;
   otherThingID : Cardinal;
end;

Về mặt chức năng, các bản ghi này hầu như luôn hoạt động như nhau (và hy vọng sẽ tiếp tục hoạt động như nhau ngay cả trong Delphi 64 bit). Nhưng số lượng rất lớn sẽ có vấn đề chuyển đổi.

Nhưng cũng có những hạn chế khi sử dụng ints không dấu. Chủ yếu xuất phát từ sự khó chịu khi trộn cả hai.

Câu hỏi thực sự là, đây có phải là một điều thực sự được suy nghĩ hoặc đưa vào thực tiễn tốt nhất? Có phải nó thường chỉ phụ thuộc vào nhà phát triển?


5
Peter, bạn đang tìm kiếm câu trả lời cụ thể Delphi?
Adam Lear

3
@Anna Hiểu cách các kiểu dữ liệu Delphi hoạt động sẽ tạo ra câu trả lời xuất sắc nhất. Tôi khá chắc chắn rằng các lập trình viên C có thể hiểu và trả lời câu hỏi này mặc dù.
Peter Turner

Câu trả lời:


9

Một lý do tại sao tôi không sử dụng các loại số nguyên không dấu trong Delphi là vì chúng có thể tạo ra các vấn đề khi trộn lẫn với các số nguyên đã ký. Đây là một trong những điều đó một lần tôi:

for i := 0 to List.Count - 1 do
  //do something here

Tôi đã ikhai báo là một số nguyên không dấu, (sau tất cả, đó là một chỉ mục vào danh sách bắt đầu từ 0, nó không bao giờ phải âm, phải không?), Nhưng khi List.Countlà 0, nó sẽ không bị đoản mạch như mong đợi vì 0 - 1đánh giá một con số thực sự cao. Giáo sư!

Giữa các vấn đề an toàn tiềm ẩn vốn có trong việc trộn các số nguyên có dấu và không dấu và các vấn đề về phạm vi, (nếu bạn sẽ cần các số dương lớn hơn high(signed whatever), rất có thể bạn cũng sẽ cần các số dương lớn hơn high(unsigned whatever)quá, nên di chuyển lên đến kích thước lớn hơn tiếp theo thay vì chuyển từ ký sang không dấu có cùng kích thước thường là hành động chính xác,) Tôi thực sự không tìm thấy quá nhiều cách sử dụng cho số nguyên không dấu khi biểu thị hầu hết dữ liệu.


2
Một phần nào đó có liên quan, một trong những rủi ro chính của việc sử dụng loại dữ liệu có khả năng nhỏ hơn mức cần thiết (trái ngược với chỉ không dấu so với đã ký) là nếu điều kiện thoát lớn hơn bạn dự định, bạn thực sự có thể kết thúc bằng một vòng lặp vô hạn khi bộ đếm tràn qua lại. Nghe có vẻ ngu ngốc, nhưng tôi đã từng viết một chương trình được cho là lặp qua mọi giá trị byte có thể và cuối cùng phải mất khoảng 15 phút để thuyết phục bản thân rằng không thể thực hiện được với bộ đếm byte.
Aaronaught

@Aaronaught: Không ở Delphi. (Ít nhất là không trừ khi bạn làm điều gì đó ngu ngốc như vô hiệu hóa kiểm tra tràn tích hợp.) Bạn sẽ kết thúc bằng một ngoại lệ khi bộ đếm tràn, thay vì một vòng lặp vô hạn. Đây vẫn là một lỗi, nhưng việc theo dõi dễ dàng hơn nhiều.
Mason Wheeler

Nếu bạn nói vậy. Tôi luôn vô hiệu hóa kiểm tra tràn trong Delphi; sau khi bị bắn phá vô tận với những thông tin sai lệch từ những thứ như mã băm và tổng kiểm tra, tôi hoàn toàn từ bỏ "tính năng" đó. Nhưng tôi cho rằng bạn đúng, nó sẽ bắt lỗi cụ thể đó.
Aaronaught

@Aaronaught: Vâng vâng, bạn muốn vô hiệu hóa nó cho những thứ như mã băm và tổng kiểm tra được thiết kế đặc biệt để tràn và bao quanh. Nhưng đối với các tính toán cho mục đích chung không được thiết kế để tràn và quấn quanh, đó là một tính năng an toàn quan trọng và tắt nó giống như lái xe không có dây an toàn.
Mason Wheeler

Có lẽ bạn đã quên, nhưng các chỉ thị biên dịch và kiểm tra tràn đã lỗi rất nhiều trong các phiên bản cũ của Delphi. Tôi có thể nhớ rất rõ việc xé tóc của mình nhiều lần sau khi thấy trình gỡ lỗi dừng trực tiếp ở giữa khối {$ O -} / {$ O +} để vui vẻ báo cáo tràn. Sau một thời gian, tôi không thể chịu đựng được nữa và vô hiệu hóa nó trên toàn cầu. Một lần nữa, yeah, nó sẽ bắt gặp vấn đề này, nhưng tôi vẫn không nghĩ rằng nó đáng giá với số lượng tích cực sai. Để mỗi của riêng mình, tất nhiên!
Aaronaught

3

Thành thật mà nói tôi có xu hướng sử dụng số nguyên theo thói quen. Tôi đã quen với thực tế rằng họ cung cấp phạm vi đủ lớn cho hầu hết các tình huống và cho phép các giá trị âm (chẳng hạn như -1). Thật vậy, rất nhiều lần sử dụng byte / word / shortint sẽ phù hợp hơn. Bây giờ nghĩ về nó tôi có thể tập trung vào những điểm này:

  • Góc nhìn cá nhân. Kích thước tilemap được giới hạn ở các ô 192x192, vì vậy tôi có thể sử dụng byte để giải quyết các ô và vòng lặp. Nhưng nếu tăng kích thước bản đồ, tôi sẽ phải trải qua mọi lần sử dụng và thay thế nó bằng từ. Khi tôi cần cho phép các đối tượng ngoài bản đồ, tôi sẽ phải quay lại để thay đổi thành smallint.

  • Vòng lặp. Tôi thường viết một vòng lặp "từ i: = 0 đến Count-1", điều gì xảy ra nếu "i" là byte và Count = 0 là vòng lặp đó chạy từ 0 đến 255. Không phải là tôi muốn nó.

  • Đồng phục. Dễ nhớ hơn và áp dụng "var i: số nguyên;" hơn là dừng lại trong từng trường hợp và nghĩ rằng "Hừm .. ở đây chúng ta đang xử lý phạm vi 0..120 .. byte .. không, chờ đã, chúng ta có thể cần -1 cho chưa được khởi tạo .. shortint .. chờ đợi .. nếu 128 là gì không đủ .. Arrgh! " hoặc "Tại sao nó lại nhỏ ở nơi này, không phải là một sự thiếu hụt?"

  • Kết hợp. Khi tôi cần kết hợp hai hoặc nhiều lớp với nhau, họ có thể sử dụng các loại dữ liệu khác nhau cho mục đích của họ, sử dụng các loại rộng hơn cho phép bỏ qua các chuyển đổi không cần thiết.

  • -1. Ngay cả khi các giá trị nằm trong phạm vi 0..n-1, tôi thường cần đặt giá trị "không có giá trị / không xác định / chưa được khởi tạo / trống", theo thông lệ -1.

Sử dụng Số nguyên cho phép bỏ qua tất cả các vấn đề này, quên đi việc tối ưu hóa ở mức độ thấp khi không cần thiết, chuyển sang cấp cao hơn và tập trung vào các vấn đề thực tế hơn.

PS Khi nào tôi sử dụng các loại khác?

  • Quầy, họ không bao giờ tiêu cực và chỉ đọc bên ngoài lớp học của họ.
  • Lý do hiệu suất / bộ nhớ, buộc phải sử dụng các loại dữ liệu ngắn hơn ở những nơi nhất định.

1

Thực tiễn tốt nhất là sử dụng loại dữ liệu phù hợp với nhu cầu cho dữ liệu đang được sử dụng (dữ liệu dự kiến).

Ví dụ về C #: Nếu tôi chỉ cần hỗ trợ 0 đến 255, tôi sẽ sử dụng một byte.

Nếu tôi cần hỗ trợ 1.000.000 tiêu cực và tích cực, thì int.

Lớn hơn 4.2 tỷ, sau đó sử dụng lâu dài.

Bằng cách chọn đúng loại, chương trình sẽ sử dụng lượng bộ nhớ tối ưu cũng như các loại khác nhau sử dụng lượng bộ nhớ khác nhau.

Đây là một tài liệu tham khảo C # int từ MSDN.

int 
 -2,147,483,648 to 2,147,483,647
 Signed 32-bit integer

uint 
 0 to 4,294,967,295
 Unsigned 32-bit integer

long 
 -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
 Signed 64-bit integer

ulong 
 0 to 18,446,744,073,709,551,615
 Unsigned 64-bit integer

Trong C # (hoặc .net nói chung) sẽ dài và ulong trở thành 128 bit trên máy 128 bit? Bởi vì trong Delphi, Integerkiểu dữ liệu là 32 bit trên máy 32 bit và rõ ràng sẽ là 64 bit trên máy 64 bit.
Peter Turner

1
@Peter Turner: Không, trong C # intchỉ là một tốc ký System.Int32, cho dù mã này chạy trên máy nào.
nikie

@nikie, nó giống như type int System.Int32hoặc một cái gì đó cho hiệu ứng đó? Nó có thể được thay đổi dễ dàng trong phiên bản tương lai của khung không?
Peter Turner

@Peter Turner / nikie (sizeof (int) .ToString ()); ==> Trả về 4 (sizeof (Int64) .ToString ()); ==> Trả về 8 Trên hệ điều hành Windows 64 bit của tôi. Là nikie, số liệu thống kê, một int thực sự là chính xác và Int32.
Jon Raynor

1
Một điều cần lưu ý đó là không phải tất cả các loại phù với Language Specification Common . uintlà một trong những loại không tuân thủ như vậy, điều đó có nghĩa là không nên sử dụng API được phơi bày công khai để tránh phá vỡ khả năng sử dụng API đó bằng các ngôn ngữ .NET khác với thư viện được viết. Đây cũng là lý do tại sao .NET framework API đang sử dụng int, nơi uintsẽ làm.
Adam Lear

1

Các loại số nguyên không được chỉ định chỉ nên được sử dụng để thể hiện các số chính trong các ngôn ngữ nơi chúng đại diện cho các số chính. Do cách các máy tính chạy C hoạt động, các kiểu số nguyên không dấu hoạt động như các thành viên của các vòng đại số mod-2 ^ n (có nghĩa là các phép tính tràn ra sẽ "bao bọc" có thể dự đoán được) và ngôn ngữ chỉ ra rằng trong nhiều trường hợp, các loại như vậy là bắt buộc phải hành xử như các vòng đại số trừu tượng ngay cả khi hành vi đó không phù hợp với hành vi của các số chính hoặc số nguyên toán học.

Nếu một nền tảng hỗ trợ đầy đủ các loại riêng biệt cho số hồng y và vòng đại số, thì tôi sẽ đề xuất rằng số hồng y nên được xử lý bằng cách sử dụng loại số hồng y (và những thứ cần bọc bằng cách sử dụng loại vòng). Các loại như vậy không chỉ có thể lưu trữ số lượng gấp đôi kích thước của các loại đã ký, mà một phương thức nhận tham số của loại đó sẽ không phải kiểm tra xem nó có âm hay không.

Tuy nhiên, do thiếu các loại số thứ tự tương đối, tốt nhất là chỉ nên sử dụng các số nguyên để biểu diễn cả số nguyên toán học và số chính.

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.