2010-08-02 38 views
5

Đây là mã rất đơn giản,Unsigned và ký so

#include <iostream> 
using namespace std; 
int main() { 
    unsigned int u=10; 
    int i; 
    int count=0; 
    for (i=-1;i<=u;i++){ 
     count++; 
    } 
    cout<<count<<"\n"; 
    return 0; 
} 

Giá trị đếm là 0. Tại sao?

+1

Ngoài ra, bạn nên sử dụng 'std :: endl' thay vì chèn' \ n' vào luồng, vì 'std :: endl' cả hai đều là di động và đảm bảo đầu ra được hiển thị ngay lập tức. –

+1

@Ben: '\ n' chỉ là di động; bạn chỉ nên sử dụng 'endl' nếu bạn đặc biệt muốn luồng này được xả sạch ngay bây giờ. –

+0

'\ n' là di động (nó được chuyển đổi thành chuỗi ngắt dòng của nền tảng) và không mang chi phí của việc xả luồng ngay lập tức. Bạn nên sử dụng cái có ngữ nghĩa bạn muốn: nếu bạn muốn dòng được xóa, sử dụng 'endl', nếu bạn chỉ muốn ngắt dòng, sử dụng' \ n'. – jalf

Trả lời

8

Cả hai toán hạng của <= phải được đề bạt vào cùng loại.

Hiển nhiên chúng được quảng cáo tới unsigned int (Tôi không có quy tắc từ tiêu chuẩn trước mặt mình, tôi sẽ tra cứu nó trong giây lát). Vì (unsigned int)(-1) <= u là sai, vòng lặp không bao giờ thực thi.

Nguyên tắc được tìm thấy trong phần 5 (expr) của tiêu chuẩn, đoạn 10, trong đó nêu (Tôi đã nêu bật sự cai trị mà áp dụng ở đây):

Nhiều nhà khai thác nhị phân mà mong đợi toán hạng số học hay kiểu liệt kê gây ra chuyển đổi và loại kết quả lợi nhuận theo cách tương tự. Mục đích là để mang lại một loại phổ biến, đó cũng là loại kết quả. mô hình này được gọi là chuyển đổi số học thông thường, được định nghĩa như sau:

  • Nếu một trong hai toán hạng là các kiểu enumeration scoped (7.2), không chuyển đổi được thực hiện; nếu toán hạng khác không có cùng kiểu, thì biểu thức này không đúng.
  • Nếu toán hạng thuộc loại dài gấp đôi, giá trị kia sẽ được chuyển đổi thành giá trị gấp đôi dài.
  • Nếu không, nếu toán hạng là gấp đôi, số còn lại sẽ được chuyển đổi thành gấp đôi.
  • Nếu không, nếu toán hạng là float, thì toán tử còn lại sẽ được chuyển thành float.
  • Nếu không, quảng cáo không thể tách rời (4.5) sẽ được thực hiện trên cả hai toán hạng. 60 Sau đó, các quy tắc sau đây sẽ được áp dụng cho các toán hạng được thăng hạng:
  • Nếu cả hai toán hạng đều có cùng loại, không cần chuyển đổi thêm.
  • Nếu không, nếu cả hai toán hạng đã ký kiểu số nguyên hoặc cả hai đều có loại số nguyên không dấu, toán hạng có loại thứ hạng chuyển đổi nguyên nhỏ hơn sẽ được chuyển thành loại toán hạng có thứ hạng lớn hơn.
  • Nếu không, nếu toán hạng có loại số nguyên không dấu có xếp hạng lớn hơn hoặc bằng thứ hạng của loại toán hạng khác, toán hạng có loại số nguyên đã ký sẽ được chuyển thành loại toán hạng với loại số nguyên không dấu .
  • Nếu không, nếu loại toán hạng có kiểu số nguyên có thể biểu thị tất cả các giá trị của loại toán hạng với loại số nguyên không dấu, toán hạng có loại số nguyên không dấu sẽ được chuyển thành loại toán hạng đã ký loại số nguyên.
  • Nếu không, cả hai toán hạng sẽ được chuyển đổi thành loại số nguyên không dấu tương ứng với loại toán hạng có kiểu số nguyên đã ký.
1

Bởi vì -1 được gán làm int không dấu nên mã vòng lặp không bao giờ được thực thi.

Cố gắng biên soạn với Wall -Wextra vì vậy bạn có thể nhận được những lời cảnh báo tương ứng (nếu không nhận được họ cho đến nay, và biên soạn với g ++)

http://en.wikipedia.org/wiki/Two's_complement

+0

cảm ơn chỉ tôi muốn hỏi bạn một điều tôi sẽ đưa ra liên kết đến câu hỏi của tôi và xin vui lòng cho tôi biết lý do tại sao họ giảm nhãn hiệu của tôi hoặc họ downvote ok? tôi muốn có được danh tiếng tốt và cố gắng đăng câu hỏi hay nhưng họ giảm bớt nó –

+1

@davit: Câu hỏi khác của bạn bị downvoted vì trình biên dịch cho bạn biết chính xác những gì đã sai (bạn đã bỏ lỡ dấu chấm phẩy) nhưng bạn đã đăng câu hỏi của mình ở đây mà không cần cố tự mình giải quyết vấn đề. –

4

Trong sự so sánh (i <= u), i được nâng cấp lên một số nguyên unsigned, và trong quá trình -1 được chuyển thành UINT_MAX.

Chuyển đổi một số tiêu cực đến một int unsigned sẽ thêm (UINT_MAX + 1) để con số đó, vì vậy -1 trở thành UINT_MAX, -2 trở thành UINT_MAX - 1, vv

Nếu bạn nghĩ về nó, người ta phải được chuyển đổi sang người khác để so sánh thậm chí làm việc, và như một quy tắc trình biên dịch chuyển đổi giá trị đã ký thành unsigned. Trong trường hợp này, tất nhiên, nó sẽ có ý nghĩa hơn để chuyển đổi giá trị unsigned để ký thay vào đó, nhưng trình biên dịch không thể quyết định theo một thông số khác dựa trên những gì bạn dự định. Bạn nên rõ ràng cast int unsigned để ký (hoặc chỉ có nó như đã ký tất cả cùng) ở đây.

+0

Quy tắc của bạn không hoạt động. Trên thực tế, 2 ** 32 được thêm vào, là 'UINT_MAX + 1', không phải' UINT_MAX - 1'. –

+0

Cảm ơn Ben, tôi đã sửa lỗi đó - thành + ngay bây giờ. – thomasrutter

+1

WRT nhận xét mới của bạn, chuyển đổi từ ký sang unsigned được xác định rõ ràng cho tất cả đầu vào, nhưng chuyển đổi từ unsigned sang signed có thể gọi hành vi được xác định thực hiện (ở đây nó sẽ không, vì giá trị của 'u' là 10 phù hợp với 'int'). –

0

Trên hệ thống có số nguyên được lưu trữ trong 4 byte, tôi tin rằng giá trị -1 bằng giá trị 2147483649 (1000 0000 0000 0000 0000 0000 0000 0001) - Đó là 1 với MSB được đặt thành 1 để biểu thị nó tiêu cực.

+1

Không, trong biểu diễn bổ sung hai của '-1' được lưu trữ như tất cả. Nhưng sự biểu diễn thực sự không quan trọng, bởi vì chuẩn C++ định nghĩa chuyển đổi từ một ký hiệu thành một kiểu tích phân không dấu như là đồng dư trong phép tính số học cơ sở-N. –

+1

Trong khi đó là đúng trên một hệ thống ký hiệu độ lớn, những hệ thống này hiện nay cực kỳ hiếm. Hầu hết các hệ thống hợp lý hiện tại sử dụng bổ sung 2 cho số nguyên, và trong trường hợp này -1 sẽ được đại diện bởi tất cả các bit được đặt thành 1 (trong trường hợp chuyển đổi từ ký sang unsigned không yêu cầu thay đổi dữ liệu, chỉ thay đổi đã giải thích). –

+1

@Jerry: cường độ đăng nhập không hề hiếm. IEEE 754 yêu cầu nó.Hầu như mọi máy tính đều sử dụng các số nguyên bổ sung twos và các biểu diễn dấu phẩy động. –

1

Điều này là do i được thăng cấp thành giá trị chưa được ký trước khi so sánh. Điều này sẽ đặt giá trị là UINT_MAX, trên máy 32 bit bằng 4294967295. Vì vậy, vòng lặp của bạn về cơ bản giống như:

// will never run 
for (i = 4294967295; i <= u; i++) { 
    count++; 
} 
Các vấn đề liên quan