2010-07-19 36 views
8

thể trùng lặp:
Could anyone explain these undefined behaviors (i = i++ + ++i , i = i++, etc…)Post-Tăng điều hành: Hành vi bất ngờ

Mã của tôi là như sau:

#include <stdio.h> 
int main() 
{ 
    int x = 10, y = 0; 
    x = x++; 
    printf("x: %d\n", x); 
    y = x++; 
    printf("y: %d\n", y); 
} 

Do tính chất của bài thặng dư, tôi mong đợi kết quả sau:

x: 10 
y: 10 

Lý do của tôi là ở dòng 5, x nên được gán cho giá trị ban đầu của nó sau khi gia tăng diễn ra.

Thay vào đó, tuy nhiên, tôi có được điều này:

x: 11 
y: 11 

Đào vào lắp ráp, điều này trông giống như một sự lựa chọn có chủ ý với tôi:

LCFI2: 
     movl $10, -4(%rbp) // this is x 
     movl $0, -8(%rbp) // this is y 
     incl -4(%rbp)  // x is simply incremented 
     movl -4(%rbp), %esi 
     leaq LC0(%rip), %rdi 
     movl $0, %eax 
     call _printf 
     movl -4(%rbp), %eax // now x is saved in a register, 
     movl %eax, -8(%rbp) // copied to y, 
     incl -4(%rbp)  // and finally incremented 
     movl -8(%rbp), %esi 
     leaq LC1(%rip), %rdi 
     movl $0, %eax 
     call _printf 

gì đang xảy ra ở đây? Có phải GCC đang cố gắng cứu tôi khỏi chính tôi? Tôi không có một tài liệu tham khảo ngôn ngữ tiện dụng nhưng tôi đã có thể nghĩ rằng điều này phá vỡ các ngữ nghĩa dự định.

+0

gớm ghiếc !!! –

+0

http://en.wikipedia.org/wiki/Sequence_point – Ken

+0

Trong những ngày cũ tồi tệ, 'a = 1 + a' trong một số ngôn ngữ nhất định là một mỏ mà tất cả các lỗi mới sẽ chạy trên đó. –

Trả lời

13

Hành vi này không được xác định vì không có điểm chuỗi can thiệp trong x = x++, xem ví dụ: số C FAQ.

+0

Cảm ơn! Trước đây tôi chưa biết về các điểm chuỗi. – danben

4

Nó không được xác định bởi ngôn ngữ C như khi nào chính xác một bài đăng/trước/giảm xảy ra. Do đó, các câu lệnh như x = x++ không được định dạng tốt - tránh chúng.

+1

Chính xác hơn, bạn không được phép sửa đổi biến nhiều lần trong một biểu thức. 6.5/2: * "Giữa điểm chuỗi trước đó và tiếp theo, đối tượng phải có giá trị được lưu trữ được sửa đổi nhiều nhất một lần bằng cách đánh giá biểu thức." * – sth

+2

@sth: Chính xác hơn, "nhiều hơn một điểm giữa các điểm chuỗi". Có thể cho một biểu thức có chứa một điểm chuỗi, trong trường hợp đó việc sửa đổi một biến nhiều hơn một lần là tốt. Ví dụ, '&&', '||' và toán tử dấu phẩy tất cả có thể tạo thành các điểm chuỗi trong một biểu thức duy nhất. –

+0

@sth: Thậm chí chính xác hơn _, đó không phải là một giới hạn trên bộ mã hóa, đó là một hạn chế đối với biến đó. Tuyên bố của bạn rằng bạn "không được phép ..." không hoàn toàn chính xác. Bạn _are_ được phép, nó chỉ là một điều rất ngớ ngẩn để làm :-) – paxdiablo

1

Khi bạn có:

a = b++; 

những gì đang xảy ra là b sẽ được lưu vào một và sau khi assigment được thực hiện b được tăng lên một. Vì vậy, nếu bạn làm:

x = x ++; 

và trước đó x là 10 gì sẽ xảy ra là 10 sẽ được lưu vào x và sau (trước khi printf của bạn được thực hiện) x được tăng lên bởi một đến 11. Đó là lý do tại sao 11 được in ra.

2

Tiêu chuẩn sang một bên (vì điều này không xác định đối với tiêu chuẩn), cách nó chạy là cách tôi mong đợi nó.

Quy tắc của ngón tay cái là đối với một phù hợp với x++, bạn thay thế x++ với x và đưa x += 1 trên dòng sau (hoặc trước dòng cho pre-increment).

Tiếp theo đó quy tắc của ngón tay cái, mã của bạn sẽ được viết như

#include <stdio.h> 
int main() 
{ 
    int x = 10, y = 0; 
    x = x; // x: 10 
    x += 1; // x: 11 
    printf("x: %d\n", x); 
    y = x; // y: 11 
    x += 1; // x: 12 
    printf("y: %d\n", y); 
} 
Các vấn đề liên quan