2016-10-07 15 views
6

tôi nghĩ rằng tôi hiểu được cách điểm chuỗi hoạt động trong C++, nhưng this GeeksQuiz question bối rối tôi:Gọi chức năng với tác dụng phụ bên trong biểu

int f(int &x, int c) { 
    c = c - 1; 
    if (c == 0) return 1; 
    x = x + 1; 
    return f(x, c) * x; 
} 

int main() { 
    int p = 5; 
    cout << f(p, p) << endl; 
    return 0; 
} 

Câu trả lời “đúng” cho câu hỏi này nói nó in 6561. Trên thực tế, trong VS2013 nó có. Nhưng không phải là UB anyway vì không có đảm bảo sẽ được đánh giá đầu tiên: f(x, c) hoặc x. Chúng tôi nhận được 6561 nếu f(x, c) được đánh giá đầu tiên: toàn bộ điều này chuyển thành năm cuộc gọi đệ quy: bốn (c = 5, 4, 3, 2) tiếp theo, cái cuối cùng (c = 1) kết thúc và trả về 1, số tiền đó là 9 ** 4 cuối cùng.

Tuy nhiên, nếu x được đánh giá trước, thì chúng tôi sẽ nhận được 6 * 7 * 8 * 9 * 1 thay thế. Điều thú vị là, trong VS2013 thậm chí thay thế f(x, c) * x với x * f(x, c) không thay đổi kết quả. Không phải là nó có nghĩa là bất cứ điều gì.

Theo tiêu chuẩn, UB này có đúng không? Nếu không, tại sao?

+2

clang cung cấp '3024' cho' x * f (x, c) '(và' 6561' cho 'f (x, c) * x'). – Holt

Trả lời

4

Đây là UB.

n4140 §1.9 [intro.execution]/15

Trừ khi có ghi chú, đánh giá của toán hạng của các nhà khai thác cá nhân và của subexpressions của cá nhân biểu là unsequenced. [...] Nếu tác dụng phụ trên đối tượng vô hướng không được kết quả liên quan đến tính toán giá trị [...] sử dụng giá trị cùng đối tượng vô hướng [...] hành vi không xác định.

Toán tử nhân không có trình tự ghi chú rõ ràng.

2

Đây là UB

Trình tự đánh giá của các toán hạng của hầu hết C++ nhà khai thác (bao gồm tự đánh giá của các đối số chức năng trong một biểu thức hàm gọi và tự đánh giá của subexpressions trong bất kỳ biểu hiện) không được chỉ định. Trình biên dịch có thể đánh giá toán hạng theo thứ tự bất kỳ và có thể chọn một thứ tự khác khi biểu thức tương tự được đánh giá lại.

Có những ngoại lệ đối với quy tắc này được ghi chú bên dưới.

Trừ khi được ghi chú bên dưới, không có khái niệm về từ trái sang phải hoặc đánh giá từ phải sang trái trong C++. Điều này không bị nhầm lẫn với tính tương hợp từ trái qua phải và từ phải sang trái của toán tử: biểu thức f1() + f2() + f3() được phân tích cú pháp thành (f1() + f2()) + f3() do kết hợp từ trái qua phải của toán tử +, nhưng hàm gọi f3 có thể được đánh giá trước, cuối hoặc giữa f1() hoặc f2() tại thời gian chạy.

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