2010-07-24 37 views
9

Tôi có đoạn code sauHành vi của một biểu thức: Được xác định hoặc Không xác định?

int m[4]={1,2,3,4}, *y; 
y=m; 
*y = f(y++); // Expression A 

Bạn tôi nói với tôi rằng Expression A có một hành vi được xác định rõ nhưng tôi không chắc chắn liệu ông là đúng.

Theo chức năng của anh ta f() giới thiệu một sequence point ở giữa và do đó hành vi được xác định rõ.

Ai đó vui lòng làm rõ.

P.S: Tôi biết chúng tôi không nên viết mã như vậy cho mục đích thực tế. Nó chỉ dành cho mục đích học tập. :)

+3

Tôi nói không. Đó là những gì 'gcc' nói với tôi. – kennytm

Trả lời

15

Tốt nhất, mã được đề cập có hành vi không xác định. Đối với các toán tử gán, "thứ tự đánh giá của toán hạng là không xác định" (C99 §6.5.16/4).

Nếu toán hạng bên trái được đánh giá trước, kết quả của f(y++) sẽ được lưu trữ trong m[0]. Nếu toán hạng bên phải được đánh giá đầu tiên, kết quả sẽ được lưu trữ trong m[1].

Đối dù hành vi này là không xác định, đoạn có liên quan là:

Giữa điểm chuỗi trước và bên cạnh một đối tượng có trách nhiệm lưu trữ giá trị Modi fi ed của nó tối đa một lần bởi việc đánh giá một biểu thức. Hơn nữa, giá trị trước sẽ được đọc chỉ để xác định giá trị được lưu trữ (C99 §6.5/2).

Nếu phía bên trái được đánh giá đầu tiên, sau đó chúng tôi chạy afoul của câu thứ hai vì thứ tự là:

  1. Giá trị của y được đọc ở phía bên trái để tới đích của nó
  2. Các Giá trị của y được đọc ở bên phải để tăng nó
  3. Có một điểm chuỗi sau khi đánh giá các đối số cho hàm (do đó, tác dụng phụ của y++ hoàn tất và y được ghi vào)

Ở bước 1, "giá trị trước" của y được đọc nhưng với mục đích khác "xác định giá trị được lưu trữ". Do đó, hành vi thực sự là không xác định bởi vì một thứ tự đánh giá hợp lệ mang lại hành vi không xác định.

+2

+1. Tôi tin rằng nó thậm chí còn không xác định, bởi vì các đánh giá của '* y' và' y ++ 'không được kết nối và sau đó gây ra một tác dụng phụ trên' y'. – avakar

+0

Cảm ơn James, câu trả lời của bạn là hoàn toàn ổn. AC :-) –

0

EDIT: điều này là không chính xác, tuy nhiên tôi để nó ở đây vì các cuộc thảo luận sau trong các ý kiến ​​là phần nào chiếu sáng, và tôi hy vọng có giá trị.

Nó được xác định rõ dựa trên thứ tự đánh giá của các toán tử trong C (hoặc C++).

Đánh giá lực lượng bài tập về phía bên tay phải của biểu thức trước tiên. Ứng dụng chức năng lực lượng đánh giá các đối số của nó đầu tiên, do đó, hiệu quả có vẻ hợp lý rõ ràng (mặc dù tôi đã không cố gắng chạy nó, vì vậy cảm thấy tự do để sửa tôi!). Chúng ta có thể viết lại này sử dụng các biến tạm thời (Tôi sẽ gọi cho họ t0 và t1), và tôi tin rằng đây có thể là rõ ràng hơn một chút:

t0 = y++; 
t1 = f(t0); 
*y = t1; 

Thuật ngữ "chuỗi điểm" là một chút của một cá trích đỏ. Một điểm chuỗi không thực sự được tạo ra, thay vì nó chỉ là hậu quả của việc có một thứ tự đánh giá nghiêm ngặt được định nghĩa cho ngôn ngữ.

EDIT: Trong khi câu trả lời này có vẻ thỏa mãn về mặt trí tuệ, câu trả lời của James McNellis trích dẫn phần có liên quan của thông số C99 nêu rõ rằng thứ tự đánh giá của bài tập là không phải là được xác định rõ. Đầy đủ tín dụng cho anh ta để thực sự kiểm tra sự thật của mình. Tôi sẽ sửa lại câu trả lời của tôi từ "nó được định nghĩa" thành "nó có thể được xác định rõ ràng đối với một trình biên dịch cụ thể", vì tôi nghĩ rằng hầu hết các trình biên dịch sẽ thường xuyên thay đổi thứ tự mà chúng phát ra mã đó (Tôi nói "có thể" để giải thích cho bất kỳ tối ưu hóa rất tích cực nào).

+2

_Xác định lực lượng đánh giá của phía bên tay phải của biểu thức đầu tiên._ Điều này không đúng: thứ tự đánh giá không được chỉ định. –

+1

Ở đâu nó nói rằng phía bên phải của một bài tập phải được đánh giá đầu tiên? – jalf

+0

Cảm ơn, tôi đã chỉnh sửa câu trả lời cho tài khoản đó và cảm ơn vì đã dạy tôi điều gì đó mới về C :) – Gian

1

Khái niệm không được xác định rõ:

Một giải thích giá trị của biểu thức là:

(1) int* t0 = y++; 
(2) int t1 = f(t0); 
(3) int& t2 = *y; 
----------------- 
t2 = t1; 

Một giải thích giá trị ngang nhau của biểu thức là:

(1) int& t2 = *y; 
(2) int* t0 = y++; 
(3) int t1 = f(t0); 
----------------- 
t2 = t1; 

Cả hai trong số này là vaalid và tạo ra các kết quả khác nhau. Vì vậy, biểu thức có kết quả không xác định.

+1

Nói chung, một biểu thức có thể có hai kết quả khác nhau chỉ có nghĩa là kết quả là * không xác định *. Tuy nhiên, trong trường hợp cụ thể này, kết quả thực sự không được xác định vì các tính toán của 't0' và' t2' có thể xảy ra theo thứ tự bất kỳ và 't0' có tác dụng phụ trên' y' trong khi 't2' sử dụng giá trị' y'. – avakar

13

Bạn hoàn toàn đúng về lời gọi hàm giới thiệu một điểm chuỗi. Tuy nhiên, điểm chuỗi đó không lưu tình huống trong trường hợp của bạn.

Hãy xem xét ví dụ đơn giản này đầu tiên

i = some_function(i++); 

Có hợp lệ? Vâng, đúng vậy. Tại sao? Nó hợp lệ vì điểm chuỗi được giới thiệu bởi hàm (cái mà bạn đang nói đến) tách hai sửa đổi của i với nhau, do đó làm cho mã hợp lệ. Không có thứ tự đánh giá nào về biểu thức này sẽ dẫn đến việc i được sửa đổi hai lần mà không có điểm chuỗi xen kẽ.

Tuy nhiên, chúng ta hãy quay trở lại biến

*y = f(y++); 

của bạn Trong trường hợp này mà điểm chuỗi tồn tại là tốt. Tuy nhiên, ngôn ngữ không đảm bảo về thứ tự đánh giá của nhà điều hành = (nghĩa là: ngôn ngữ không đảm bảo về toán hạng của toán tử gán được đánh giá đầu tiên: trái hoặc phải). Nó là khá cho phép cho trình biên dịch để đánh giá phía bên trái đầu tiên (*y), đối số hàm thứ hai (y++), sau đó gọi hàm và sau đó thực hiện nhiệm vụ thực tế. Trong kịch bản tiềm năng này, hai bước đầu tiên - đọc số y và sửa đổi y - không được phân tách bằng một điểm chuỗi. Do đó, hành vi là không xác định.

+1

@Ben Voigt: Tôi đã nói về thứ tự tương đối của việc đánh giá toán hạng của toán tử '=', tức là LHS hay RHS được đánh giá trước. – AnT

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