Sự khác biệt giữa int có dấu và không dấu là gì


91

Sự khác biệt giữa int có dấu và không được ký là gì?


5
Đây là một câu hỏi thực sự, và câu trả lời không đơn giản như vậy mà khá tinh tế.
R .. GitHub DỪNG TRỢ GIÚP ICE

Bỏ phiếu để mở lại. Nó có thể là một bản sao, nhưng nó chắc chắn là một câu hỏi thực sự.
Brian


Cần thêm nhiều thẻ vì nhiều ngôn ngữ sử dụng chúng.
Juan Boero

Câu hỏi này có thể cần một chương để giải thích. Nếu bạn muốn biết thông tin chi tiết, hãy kiểm tra Số nguyên chưa ký và đã ký để được giải thích thêm.
ẩn danh

Câu trả lời:


113

Như bạn có thể biết, ints được lưu trữ bên trong dưới dạng nhị phân. Thông thường, một intchứa 32 bit, nhưng trong một số môi trường có thể chứa 16 hoặc 64 bit (hoặc thậm chí là một số khác, thường nhưng không nhất thiết phải là lũy thừa của hai).

Nhưng đối với ví dụ này, chúng ta hãy xem xét các số nguyên 4 bit. Nhỏ xíu, nhưng hữu ích cho mục đích minh họa.

Vì có bốn bit trong một số nguyên như vậy, nó có thể giả sử một trong 16 giá trị; 16 là hai đến lũy thừa thứ tư, hoặc 2 nhân 2 lần 2 nhân 2. Những giá trị đó là gì? Câu trả lời phụ thuộc vào việc số nguyên này là a signed inthay an unsigned int. Với an unsigned int, giá trị không bao giờ âm; không có dấu hiệu liên quan đến giá trị. Dưới đây là 16 giá trị có thể có của một bốn bit unsigned int:

bits  value
0000    0
0001    1
0010    2
0011    3
0100    4
0101    5
0110    6
0111    7
1000    8
1001    9
1010   10
1011   11
1100   12
1101   13
1110   14
1111   15

... và Đây là 16 giá trị có thể có của một bốn bit signed int:

bits  value
0000    0
0001    1
0010    2
0011    3
0100    4
0101    5
0110    6
0111    7
1000   -8
1001   -7
1010   -6
1011   -5
1100   -4
1101   -3
1110   -2
1111   -1

Như bạn thấy, đối với signed ints, bit quan trọng nhất là 1nếu và chỉ khi số âm. Đó là lý do tại sao, đối với signed ints, bit này được gọi là "bit dấu".


11
Có lẽ điều đáng nói là đây là định dạng bổ sung của cả hai, được thừa nhận là ngày nay được sử dụng rộng rãi. Cũng có nhiều cách khác để biểu diễn số nguyên có dấu, đáng chú ý nhất là phần bù của một người.
SCHEDLER

Chính xác. Và tiêu chuẩn ISO9899 C thậm chí không yêu cầu phải sử dụng phần bổ sung của một hoặc hai phần; bất kỳ quy ước nào khác thực sự hoạt động đều được phép.
Bill Evans tại Mariposa

1
Mặc dù phần bù của hai là không bắt buộc, nhưng (unsigned)(-1)được yêu cầu là giá trị có thể biểu diễn lớn nhất cho unsigned(không phụ thuộc vào biểu diễn nhị phân), điều này đúng với phần bù của 2, chứ không phải các biểu diễn khác.
rubenvb

3
@BillEvansatMariposa: Tiêu chuẩn nói rằng đối với số nguyên có dấu, có 3 biểu diễn được phép: dấu + độ lớn, phần bù của 2, phần bù của 1. Bất kỳ khác sẽ phải vô hình cho chương trình và được coi là một trong những 3.
Alexey Frunze

Ok nhưng dưới mui xe! Điều gì đang thực sự xảy ra! Sự khác biệt giữa số ĐÃ KÝ và CHƯA KÝ! Máy quản lý việc tính toán như thế nào? Nó chỉ trừ một giá trị từ một giá trị khác? Sự khác biệt giữa 1111 = 15 và 1111 = -1 như thế nào?
Mihail Georgescu

19

intunsigned intlà hai kiểu số nguyên riêng biệt. ( intcũng có thể được gọi là signed int, hoặc chỉ signed; unsigned intcũng có thể được gọi là unsigned.)

Như tên ngụ ý, intlà một kiểu số nguyên, và unsigned intlà một unsigned kiểu số nguyên. Điều đó có nghĩa intlà có thể đại diện cho các giá trị âm và chỉ unsigned intcó thể đại diện cho các giá trị không âm.

Ngôn ngữ C đặt ra một số yêu cầu đối với phạm vi của các loại này. Phạm vi của intphải có ít nhất -32767.. +32767, và phạm vi của unsigned intphải có ít nhất 0.. 65535. Điều này ngụ ý rằng cả hai loại phải có ít nhất 16 bit. Chúng là 32 bit trên nhiều hệ thống, hoặc thậm chí 64 bit trên một số hệ thống. intthường có thêm một giá trị âm do biểu diễn bổ sung của hai được sử dụng bởi hầu hết các hệ thống hiện đại.

Có lẽ sự khác biệt quan trọng nhất là hành vi của số học có dấu và không dấu. Đối với đã ký int, tràn có hành vi không xác định. Đối với unsigned int, không có tràn; chẳng hạn như bất kỳ thao tác nào mang lại giá trị nằm ngoài phạm vi của kiểu UINT_MAX + 1U == 0U.

Bất kỳ kiểu số nguyên nào, có dấu hoặc không dấu, lập mô hình một dải con của tập hợp vô hạn các số nguyên toán học. Miễn là bạn đang làm việc với các giá trị trong phạm vi của một loại, mọi thứ đều hoạt động. Khi bạn tiếp cận giới hạn dưới hoặc giới hạn trên của một loại, bạn gặp phải sự gián đoạn và bạn có thể nhận được kết quả không mong muốn. Đối với các kiểu số nguyên có dấu, vấn đề chỉ xảy ra đối với các giá trị âm và dương rất lớn, vượt quá INT_MININT_MAX. Đối với các kiểu số nguyên không dấu, vấn đề xảy ra đối với các giá trị dương rất lớn và bằng không . Đây có thể là một nguồn lỗi. Ví dụ, đây là một vòng lặp vô hạn:

for (unsigned int i = 10; i >= 0; i --) [
    printf("%u\n", i);
}

iluôn luôn lớn hơn hoặc bằng số không; đó là bản chất của các loại không dấu. (Bên trong vòng lặp, khi nào ibằng 0, hãy i--đặt giá trị của nó thành UINT_MAX.)


12

Đôi khi chúng ta biết trước rằng giá trị được lưu trữ trong một biến số nguyên nhất định sẽ luôn là số dương - chẳng hạn khi nó được sử dụng để chỉ đếm mọi thứ. Trong trường hợp này, chúng ta có thể khai báo biến là không có dấu, như trong unsigned int num student;,. Với khai báo như vậy, phạm vi giá trị số nguyên được phép (đối với trình biên dịch 32 bit) sẽ chuyển từ phạm vi -2147483648 đến +2147483647 thành phạm vi 0 đến 4294967295. Do đó, việc khai báo một số nguyên là không dấu gần như tăng gấp đôi kích thước lớn nhất có thể giá trị mà nó có thể giữ.


@Alex Tôi đã ở giữa chỉnh sửa câu trả lời đó 10 phút trước và nó giống hệt nhau. lol
Skuld,

12

Theo thuật ngữ của giáo dân, int không dấu là một số nguyên không thể âm và do đó có phạm vi giá trị dương cao hơn mà nó có thể giả định. Một int có dấu là một số nguyên có thể âm nhưng có phạm vi dương thấp hơn để đổi lấy nhiều giá trị âm hơn mà nó có thể giả định.


0

Trong thực tế, có hai điểm khác biệt:

  1. in (ví dụ với couttrong C ++ hoặc printfC): đại diện nguyên chút unsigned được hiểu như là một số nguyên không âm bởi các chức năng in.
  2. đặt hàng : việc đặt hàng phụ thuộc vào đặc điểm kỹ thuật đã ký hoặc chưa ký.

mã này có thể xác định số nguyên bằng cách sử dụng tiêu chí sắp xếp:

char a = 0;
a--;
if (0 < a)
    printf("unsigned");
else
    printf("signed");

Nếu điều này giải thích sự khác biệt với một giao dịch bằng số âm và khác, không. Nó sẽ giúp ích cho bài viết này rất nhiều.
Daniel Jackson

@DanielJackson Không rõ bạn nói gì. một char có thể được coi là âm hoặc dương tùy thuộc vào trình biên dịch. đầu ra của mã phụ thuộc vào những gì trình biên dịch chọn và điều này cho thấy sự khác biệt giữa có dấu và không có dấu.
Minimus Heximus
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.