Điều gì xảy ra nếu tôi gán giá trị âm cho một biến không dấu?


81

Tôi rất tò mò muốn biết điều gì sẽ xảy ra nếu tôi gán giá trị âm cho một biến không dấu.

Mã sẽ giống như thế này.

unsigned int nVal = 0;
nVal = -5;

Nó không cho tôi bất kỳ lỗi trình biên dịch nào. Khi tôi chạy chương trình, nó nValđã được gán một giá trị lạ! Có thể là giá trị bổ sung của một số 2 được gán cho nVal?


1
Linh cảm của tôi (vẫn chưa thể tìm thấy nó trong tiêu chuẩn) là hành vi về mặt kỹ thuật là không xác định. Hơn nữa, tôi nghi ngờ rằng bạn sẽ thấy những gì bạn mong đợi trên bất kỳ trình biên dịch nào bạn có thể tìm thấy. Vì vậy, mặc dù bạn thường thấy hành vi đó, nhưng có lẽ không phải là một ý kiến ​​hay nếu bạn dựa vào nó.
sblom

6
Nó không phải là không xác định (xem §4.7 / 2 ), nhưng biểu diễn (ví dụ phần bổ sung 2s) không bắt buộc theo tiêu chuẩn.
Georg Fritzsche

@gf (và cộng sự bên dưới), thật tuyệt. Trên thực tế, có vẻ như hành vi được xác định rõ ràng là những gì bạn mong đợi, @viswanathan.
sblom

3
Dòng thứ hai tương đương với nVal = (unsigned int) -5;. Tập hợp của -5to unsigned intđược xác định trong 6.3.1.3. Việc biểu diễn trong phần bù 2s không bắt buộc theo tiêu chuẩn nhưng thuật toán để chuyển đổi thành không dấu là: "giá trị được chuyển đổi bằng cách cộng hoặc trừ lặp lại một giá trị lớn hơn giá trị lớn nhất có thể được biểu diễn trong kiểu mới cho đến khi giá trị nằm trong phạm vi của kiểu mới. "
Pascal Cuoq,

1
@Pascal: Có vẻ như bạn đang đề cập đến C99, nhưng câu hỏi được gắn thẻ C ++.
Georg Fritzsche

Câu trả lời:


67

Để có câu trả lời chính thức - Phần 4.7 liên kết chuyển đổi

"Nếu kiểu đích là không dấu, giá trị kết quả là số nguyên không dấu nhỏ nhất tương ứng với số nguyên nguồn (modulo 2 n trong đó nsố bit được sử dụng để biểu thị kiểu không dấu). [Lưu ý: Trong biểu diễn phần bù của một số nguyên, chuyển đổi này là khái niệm và không có thay đổi trong mẫu bit (nếu không có sự cắt bớt). —end note]

Điều này về cơ bản có nghĩa là nếu kiến ​​trúc cơ bản lưu trữ trong một phương thức không phải là Phần bổ sung của Hai (như Tầm quan trọng đã ký, hoặc Phần bổ sung của Một), thì việc chuyển đổi thành không được ký phải hoạt động như thể đó là Phần bổ sung của Hai.


37
Số nguyên không dấu nhỏ nhất đồng dư với số nguyên nguồn có nghĩa là gì?
David Rodríguez - dribeas

11
@ DavidRodríguez-dribeas Ví dụ: 5 và 3 là "đồng dư mod 2" vì 5% 2 và 3% 2 đều là 1.
JoeQuery 19/1113

Nó liên quan đến những phiên bản nào của tiêu chuẩn C ++? Tất cả?
Alexey Kruglov

36

Nó sẽ gán mẫu bit đại diện cho -5 (trong phần bù của 2) cho int không dấu. Đó sẽ là một giá trị lớn không có dấu. Đối với các int 32 bit, giá trị này sẽ là 2 ^ 32 - 5 hoặc 4294967291


2
Bit không có gì để làm với nó.
GManNickG

1
@BenVoigt: Đủ công bằng, ý tôi là nó không liên quan gì đến cách các bit được diễn giải. (Nghĩa là, "bit" trong phần được trích dẫn chỉ là viết tắt củaceil(log_2(x)) .)
GManNickG

1
@GManNickG Bit's (như trong, thuộc về bit)? 2's Compliment (đó là điều rất tốt của bạn) ? GAAAAAAAAAAAAAH!
NullUserException

1
@NullUserException: Haha, tôi biết. Viết "* s" thay cho "* s" là một thói quen tồi tệ mà tôi đã có trong một thời gian. Đối với lời khen ngợi thay vì bổ sung, đó chỉ là tomfoolery thuần túy. :)
GManNickG

Đơn giản là chìa khóa. Câu trả lời này có cái đó. (2 ^ 32 - 5) giải thích hành vi này tốt hơn là trích dẫn tài liệu.
Redhart

4

Nó sẽ hiển thị dưới dạng số nguyên dương có giá trị của số nguyên không dấu tối đa - 4 (giá trị phụ thuộc vào kiến ​​trúc máy tính và trình biên dịch).

BTW
Bạn có thể kiểm tra điều này bằng cách viết một chương trình loại C ++ đơn giản "hello world" và tự xem


Tôi đã viết và kiểm tra đó là lý do tại sao tôi đặt câu hỏi nhưng tôi không biết làm thế nào trình biên dịch đạt được giá trị dương đó. Cảm ơn
ckv

6
Thật không may với C ++, viết chương trình để kiểm tra hành vi không phải lúc nào cũng là một ý kiến ​​hay. Ví dụ: nếu một người cố gắng kiểm tra những gì xảy ra trong trường hợp tràn đã ký , nó sẽ dẫn đến hành vi không xác định, hành vi này không được đảm bảo là giống nhau trên mọi máy / trình biên dịch.
Ben Jones,

4

Bạn nói đúng, số nguyên có dấu được lưu trữ ở dạng bổ sung của 2 và số nguyên không dấu được lưu trữ trong biểu diễn nhị phân không dấu . C (và C ++) không phân biệt giữa hai, vì vậy giá trị bạn nhận được chỉ đơn giản là giá trị nhị phân không dấu của biểu diễn nhị phân bổ sung của 2.


16
Nó có thể không được lưu trữ trong lời khen của 2.
GManNickG

Nó có nghĩa là gì nếu một cái gì đó được "lưu trữ trong 2's?" @GManNickG
JeremyF

4
@JeremyF: Không phải "2's", "2's khen". Đó là một thuật ngữ Google có thể sử dụng và là một cách biểu thị các số nguyên có dấu.
GManNickG

2

Vâng, bạn chính xác. Giá trị thực tế được gán giống như tất cả các bit được đặt ngoại trừ giá trị thứ ba. -1 là tất cả các bit được thiết lập (hex: 0xFFFFFFFF), -2 là tất cả các bit ngoại trừ bit đầu tiên, v.v. Những gì bạn sẽ thấy có lẽ là giá trị hex 0xFFFFFFFB ở dạng thập phân tương ứng với 4294967291.


3
Bit không liên quan gì đến nó, biểu diễn số nguyên không được chỉ định.
GManNickG

2
Câu trả lời của bạn là chính xác, chặt chẽ, đến mức và điều mà tôi sẽ không bao giờ sử dụng trong lớp.
Martin

xem câu trả lời của tôi cho phần bù của 2 là -5. Tôi không nghĩ rằng bạn đã làm đúng phép toán của mình trên các giá trị nhị phân ở đây.
cynistersix

0

Khi bạn gán một giá trị âm cho một biến không dấu thì nó sẽ sử dụng phương thức bổ sung 2 để xử lý và trong phương pháp này, nó chuyển tất cả 0 thành 1 và tất cả 1 thành 0 rồi thêm 1 vào đó. Trong trường hợp của bạn, bạn đang xử lý int có 4 byte (32 bit) vì vậy nó cố gắng sử dụng phương pháp bổ sung của 2 trên số 32 bit khiến bit cao hơn bị lật. Ví dụ:

┌─[student@pc]─[~]
└──╼ $pcalc 0y00000000000000000000000000000101      # 5 in binary
        5                       0x5                     0y101
┌─[student@pc]─[~]
└──╼ $pcalc 0y11111111111111111111111111111010      # flip all bits  
      4294967290      0xfffffffa      0y11111111111111111111111111111010
┌─[student@pc]─[~]
└──╼ $pcalc 0y11111111111111111111111111111010 + 1  # add 1 to that flipped binarry
      4294967291      0xfffffffb      0y11111111111111111111111111111011
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.