2010-09-08 30 views
8
signed int x= -5; 
unsigned int y=x; 

giá trị của y là gì? và làm thế nào?Giá trị chưa ký và chữ ký trong C (đầu ra là gì)

+5

Khi bạn cố gắng này, Bạn đã thấy gì? –

+4

@KennyTM, không được xác định thực hiện; truyền từ một unsigned int đến một int đã ký mà không thể đại diện cho nó được thực hiện xác định, nhưng cách khác xung quanh (signed -> unsigned) được xác định rõ. – bdonlan

+2

@bdonlan: 'UINT_MAX' * là * triển khai được xác định. – kennytm

Trả lời

-1

y = 0xfffffffb đó là biểu diễn nhị phân là -5 (hai của bổ sung)

+0

Có thể bạn vui lòng giải thích thêm .... –

+1

Kết quả không phụ thuộc vào bất kỳ "biểu diễn nhị phân" nào. Kết quả được quyết định bởi các yêu cầu của tiêu chuẩn ngôn ngữ. Và tiêu chuẩn này khá rõ ràng trong trường hợp này. – AnT

+0

@AndreyT. Để công bằng, mặc dù nó không được nói như vậy, chắc chắn là sự bổ sung của 2 -> kết quả chuyển đổi chưa được ký trong cùng một mẫu bit (tôi nghĩ tiêu chuẩn C++ đề cập đến điều này trong quá trình chuyển đổi, không thể nhớ tiêu chuẩn C có). Mô tả của Philibert tương đương với định nghĩa trong tiêu chuẩn: bạn có thể chuyển đổi chữ ký -> unsigned bằng cách làm việc trong phần bù 2 của giá trị đã ký, sau đó đọc nó như một giá trị chưa ký. Ông không bao giờ nói đó là cách thực hiện thực hiện nó (mặc dù không có nghi ngờ 2 bổ sung thực hiện). –

16

Nó phụ thuộc vào giá trị tối đa của unsigned int. Thông thường, một unsigned int là 32-bit dài, do đó các UINT_MAX là 2 − 1. Các tiêu chuẩn C (§ 6.3.1.3/2) đòi hỏi một ký → chuyển đổi unsigned được thực hiện như

Ngược lại, nếu loại mới chưa được ký, giá trị được chuyển đổi bằng cách liên tục cộng hoặc trừ nhiều hơn giá trị lớn nhất có thể được thể hiện trong loại mới cho đến khi giá trị nằm trong phạm vi của loại mới.

Do đó y = x + ((2 − 1) + 1) = 2 − 5 = 4294967291.


Trong một nền tảng 2's complement, mà hầu hết các trường ngày nay, y cũng giống như đại diện bổ sung 2 của x.

-5 = ~ 5 + 1 = 0xFFFFFFFA + 1 = 0xFFFFFFFB = 4294967291.

2

Giá trị của yUINT_MAX - 5 + 1, ví dụ: UINT_MAX - 4.

Khi bạn chuyển đổi giá trị số nguyên đã ký thành loại không dấu, giá trị được giảm modulo 2^N, trong đó N là số bit tạo giá trị trong loại không dấu. Điều này áp dụng cho cả giá trị được ký âm và dương.

Nếu bạn đang chuyển đổi từ loại hình ký hợp đồng với loại unsigned có cùng kích thước, ở trên có nghĩa là giá trị ký kết tích cực vẫn không thay đổi (+5 được chuyển đổi sang 5, ví dụ) và giá trị âm được thêm vào MAX + 1, nơi MAX là giá trị tối đa của loại không dấu (-5 được chuyển đổi thành MAX + 1 - 5).

4

Từ tiêu chuẩn C99:

6.3.1.3 Signed và số nguyên unsigned

  1. Khi một giá trị với kiểu số nguyên được chuyển đổi sang một số nguyên kiểu khác hơn _Bool, nếu giá trị có thể được thể hiện bằng loại mới, nó không thay đổi.
  2. Nếu không, nếu loại mới là unsigned, giá trị được chuyển đổi bởi nhiều lần thêm hoặc trừ một nhiều hơn giá trị tối đa có thể được biểu diễn trong các loại hình mới đến khi giá trị nằm trong khoảng của kiểu mới . 49)

49) Quy tắc mô tả số học trên giá trị toán học, không phải là giá trị của một loại biểu thức nhất định.

Vì vậy, bạn sẽ xem xét, hiệu quả, y = x + UINT_MAX + 1. Điều này chỉ có nghĩa là đại diện bổ sung twos được sử dụng không thay đổi như một số nguyên không dấu, điều này làm cho nó rất nhanh trên hầu hết các máy tính hiện đại, vì chúng sử dụng bổ sung twos cho các số nguyên đã ký.

+3

Bạn đang thiếu một: UINT_MAX là 2^N-1. –

+0

Không hoàn toàn chính xác. Công thức đúng là 'y = x + UINT_MAX - 1'. – AnT

+1

@AndreyT: Trên thực tế, công thức chính xác là 'y = x + UINT_MAX + 1'. – kennytm

1

giá trị Signed thường được lưu trữ như một cái gì đó gọi là two's complement: số bổ sung

Hai của là một cách để mã hóa số âm vào nhị phân thông thường, chẳng hạn rằng việc bổ sung vẫn hoạt động. Thêm -1 + 1 phải bằng 0, nhưng bổ sung thông thường cho kết quả của 2 hoặc -2 trừ khi thao tác nhận thông báo đặc biệt của bit dấu và thực hiện phép trừ thay thế. Bổ sung của hai kết quả trong tổng số chính xác mà không có bước bổ sung này.

Điều này có nghĩa rằng các đại diện thực tế của số -5 và 4294967291 trong bộ nhớ (đối với một từ 32 bit) là giống nhau, ví dụ: 0xFFFFFFFB hoặc 0b11111111111111111111111111111011. Vì vậy, khi bạn thực hiện:

unsigned int y = x; 

Nội dung của x được sao chép đúng nguyên văn, tức là bitwise thành y. Điều này có nghĩa là nếu bạn kiểm tra các giá trị thô trong bộ nhớ của xy chúng sẽ giống hệt nhau. Tuy nhiên, nếu bạn làm như vậy:

unsigned long long y1 = x; 

giá trị của x sẽ được gia hạn đăng nhập trước khi được chuyển đổi thành dài không ký. Trong trường hợp phổ biến khi lâu dài là 64 bit, điều này có nghĩa là y1 bằng 0xFFFFFFFFFFFFFFFB.

Điều quan trọng cần lưu ý điều gì xảy ra khi truyền sang loại lớn hơn. Giá trị đã ký được truyền tới giá trị đã ký lớn hơn sẽ được mở rộng bằng ký. Điều này sẽ không xảy ra nếu giá trị nguồn là unsigned, ví dụ .:

unsigned int z = y + 5; 
long long z1 = (long long)x + 5; // sign extended since x is signed 
long long z2 = (long long)y + 5; // not sign extended since y is unsigned 

zz1 sẽ bằng 0 nhưng z2 sẽ không. Điều này có thể được khắc phục bằng cách đúc các giá trị để ký trước mở rộng nó:

long long z3 = (long long)(signed int)y + 5; 

hoặc loại suy nếu bạn không muốn mở rộng dấu hiệu xảy ra:

long long z4 = (long long)(unsigned int)x; 
+1

Nhưng câu hỏi là về chuyển đổi thành loại * unsigned *. Tuy nhiên, trong câu trả lời, bạn chỉ đề cập đến các chuyển đổi đối với các loại * đã ký *. – AnT

+0

Tôi cầu xin sự khác biệt, mặc dù tôi tập trung phản hồi của tôi phần nào vào chuyển đổi cho các loại đã ký vì đó là nơi có rồng. Tôi cũng không nghĩ rằng phản ứng của tôi xứng đáng với nhược điểm nhưng tôi thiên vị. –

+0

+1: cho "bổ sung hai", ngay cả khi thực sự từ ngữ evasive của C99 cho một định nghĩa mà cũng sẽ làm việc với một trình biên dịch có thể sử dụng nói BCD.Tôi tự hỏi là trình biên dịch C như vậy tồn tại anyway, cho đến khi chứng minh sai tôi tin rằng tất cả các trình biên dịch C hiện đang sử dụng bổ sung của hai. – kriss

Các vấn đề liên quan