2013-08-25 30 views
14

Tôi có mã sau đây.Lý do cho đầu ra này là gì?

int x=80; 
    int &y=x; 
    x++; 
    cout<<x<<" "<<--y; 

Kết quả đầu ra là 80 80. Và tôi không hiểu làm thế nào. Tôi nghĩ rằng đầu ra của x sẽ là 81 mặc dù tôi không biết gì về y. Biến tham chiếu bị ảnh hưởng bởi toán tử giảm dần như thế nào. Ai đó có thể xin giải thích?

+1

Có lẽ câu hỏi này sẽ giúp làm rõ nó cho bạn: Sự khác nhau giữa biến con trỏ và biến tham chiếu trong C++ là gì? (http://stackoverflow.com/questions/57483/what-are-the-differences-between-pointer-variable-and-reference-variable-in-c) – yasouser

+0

Điều này tương tự (với http://stackoverflow.com/câu hỏi/18426473/pre-increment-not-working-as-i-expect/18426505 # 18426505). Bạn đang thiếu điểm chuỗi. –

Trả lời

6

Một điều khó chịu về các toán tử chuyển hướng << là chúng trực giác truyền tải một indea "tính toán tuần tự" thực sự không có mặt.

Khi bạn viết

std::cout << f() << g() << std::endl; 

các đầu ra sẽ hiển thị đầu tiên là kết quả của f() và sau đó kết quả của g(), nhưng các cuộc gọi thực tế để g() có thể xảy ra trước khi cuộc gọi đến f().

Nó thậm chí còn tồi tệ hơn điều này ... nó không phải là trình tự không thể dự đoán được, nhưng đó thực sự là khái niệm về chuỗi rất không hợp lệ. Trong

std::cout << f(g()) << h(i()) << std::endl; 

đó là ví dụ pháp lý rằng chức năng đầu tiên được gọi là g(), tiếp theo là i(), tiếp theo là h() và cuối cùng bởi f(). Nó thậm chí không được bảo đảm rằng thứ tự sẽ giống nhau cho tất cả các yêu cầu (không phải vì các nhà sản xuất trình biên dịch thích thú với bạn, nhưng vì mã có thể được gạch chân và trình biên dịch có thể quyết định thứ tự khác nếu hàm chứa được in trong một ngữ cảnh khác).

C++ nhà khai thác duy nhất mà đảm bảo một chuỗi theo thứ tự đánh giá bao gồm:

  1. &&: đầu tiên đánh giá ở phía bên trái và chỉ khi kết quả là "true" đánh giá phía bên phải
  2. ||: đánh giá lại đầu tiên bên trái và chỉ khi kết quả là "sai" đánh giá bên phải
  3. ?:: đánh giá điều kiện đầu tiên và sau đó chỉ toán hạng hai hoặc toán hạng ba
  4. ,: toán tử dấu phẩy ... đánh giá bên trái, giảm giá trị và sau đó đánh giá và trả về phía bên phải. LƯU Ý: dấu phẩy giữa các tham số hàm KHÔNG phải là toán tử dấu phẩy và không có lệnh đánh giá nào được áp đặt.

Ngoài ra guaratee này chỉ hợp lệ cho các toán tử được xác định trước. Nếu bạn quá tải &&, || hoặc , trong lớp học của bạn, họ chỉ là các nhà khai thác bình thường mà không có bất kỳ hạn chế đặc biệt nào đối với đơn hàng đánh giá.

Bất kỳ nhà khai thác mạng nào khác cũng không áp đặt bất kỳ hạn chế nào đối với đơn hàng đánh giá và điều này bao gồm << ngay cả khi bạn sử dụng các thủ thuật như vậy.

19

Khái niệm được đánh giá là:

((cout << x) << " ") << --y; 

Không có điểm chuỗi (hoặc đặt hàng) giữa đánh giá của phía bên trái và bên phải của biểu thức, trình biên dịch có thể đầu ra mã đánh giá --y là bước đầu tiên.

Kể từ y là tham chiếu đến x ở đây, đây thực sự là hành vi không xác định vì bạn vừa đọc và ghi sang x trong cùng một biểu thức mà không can thiệp vào các điểm chuỗi.

+0

Vui lòng kiểm tra mã đã chỉnh sửa Điều này chắc chắn có một số điều cần làm với số học con trỏ. Khi chúng tôi nói y có địa chỉ x, 80 và thử và giảm y, nó cũng không giảm trên hệ thống của tôi. –

+4

@SanyamGoel: đó là hành vi không xác định. Các trình biên dịch khác nhau có thể (và sẽ) xuất ra những thứ khác nhau. Thứ tự đánh giá của LHS và RHS được xác định thực hiện, cộng với đọc và ghi vào 'x' mà không có các điểm chuỗi => hành vi không xác định (nghĩa là nó không đúng C++, nó có thể làm bất cứ điều gì). – Mat

+0

Chỉnh sửa được đề xuất: * "Xem [chủ đề SO này] (http://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points) để có giải thích chi tiết."* – jrok

1

Đây là hành vi không xác định, C/C++ tiêu chuẩn không xác định đối số cách được đẩy vào ngăn xếp, và thường lập luận được đẩy theo thứ tự ngược lại, ví dụ ở đây:

func(1, 2) 

sẽ được đánh giá một cái gì đó như:

push 2 
push 1 
call func 

như vậy trong trường hợp của bạn, --y được đánh giá và đẩy trước x làm. Rõ ràng trong ví dụ này:

#include <iostream> 

int a() { std::cout << "a" << std::endl ; return 1; } 
int b() { std::cout << "b" << std::endl ; return 2; } 

int main(void) { 

    std::cout << a() << " " << b() << std::endl; 

    return 0; 
} 

từ cái nhìn đầu tiên, nó sẽ in:

a 
b 
1 2 

nhưng nó in:

b 
a 
1 2 
0
x++ 

increments x và sản xuất như biểu thức kết quả giá trị ban đầu của x.

Cụ thể, cho x ++ không có thứ tự thời gian ngụ ý cho việc tăng và sản xuất giá trị ban đầu của x. Trình biên dịch miễn phí phát ra mã máy tạo ra giá trị ban đầu của x, ví dụ: nó có thể có mặt trong một số thanh ghi, và làm chậm trễ cho đến khi kết thúc biểu thức (điểm thứ tự tiếp theo). Mặc dù x++ dường như tăng x đến , nó không hoạt động cho đến khi in. Theo các --y, nó nhận được giá trị gia tăng (81) và giảm nó trước khi in nó vì nó là một tiền tố tiền tố.

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