X sau khi x = x ++ là gì?


285

Điều gì xảy ra (đằng sau tấm màn) khi điều này được thực thi?

int x = 7;
x = x++;

Đó là, khi một biến được tăng lên và được gán cho chính nó trong một câu lệnh? Tôi đã biên soạn và thực hiện điều này. xvẫn là 7 ngay cả sau khi toàn bộ tuyên bố . Trong cuốn sách của tôi, nó nói rằng nó xđược tăng lên!


9
Hãy thử điều này int x = 7; x = ++x;:, tất nhiên vẫn là mã khủng khiếp, bạn không cần phải gán lại. int x = 7; x++;Là đủ.
stivlo

7
Đây là một thực tế tồi tệ, không tăng biến trong cùng một dòng bạn sử dụng nó.
Yousf

5
Tôi muốn sử dụng x += 1, ngoại trừ có thể trong các vòng lặp. for(int x=0; x<7; x++)
Svish

2
@andyortlieb không có đối tượng, chỉ là một giá trị cơ bản.
fortran

Câu trả lời:


301

xkhông được tăng lên. Nhưng bạn đang gán giá trị cũ xtrở lại vào chính nó.


x = x++;
  1. x++tăng xvà trả về giá trị cũ của nó.
  2. x = gán giá trị cũ trở lại chính nó.

Vì vậy, cuối cùng, xđược gán trở lại giá trị ban đầu của nó.


3
Sau đó, bạn sẽ nói gì về x = ++ x;
Hisham Muneer

3
@HishamMuneer xđược tăng lên trước khi nó được đọc trong trường hợp đó, vì vậy bạn kết thúc với x + 1.

@HishamMuneer Đã quá muộn. Nhưng tôi đang đặt nó ở đây vì nó có thể hữu ích cho một số người khác, những người sẽ tìm kiếm trong tương lai. Cách tốt nhất để giải quyết vấn đề này là nhìn vào mã lắp ráp được tạo cho x = x ++ và x = ++ x. Xin vui lòng xem câu trả lời của Thinkingcap.
nantitv

Tôi biết điều này là siêu cũ, nhưng tôi có một câu hỏi. Là thứ tự trên của hoạt động được đảm bảo bởi các tiêu chuẩn? Có thể là bài tập được thực hiện trước khi tăng?
Vũ khí ngọc lục bảo

@EmeraldWeapon Nó được định nghĩa trong Java. Chỉ có trong C / C ++, bạn mới thấy loại shenanigans đó.
Bí ẩn

385
x = x++;

tương đương với

int tmp = x;
x++;
x = tmp;

46
Lol, yay cho định nghĩa đệ quy. có lẽ bạn nên thực hiện x=x+1thay vìx++
user606723

8
@ user606723: Không. Tôi có nghĩa là toàn bộ tuyên bố x = x++, không chỉ là tăng bài x++.
Hoàng tử John Wesley

20
Tôi không nghĩ rằng đây là tất cả những gì hữu ích mà không cần giải thích thêm. Chẳng hạn, nó không đúng x = ++x;cũng tương đương với int tmp = x; ++x; x = tmp;, vậy theo logic nào chúng ta có thể suy luận rằng câu trả lời của bạn là đúng (đó là gì)?
kvb

4
thậm chí rõ ràng hơn là trong asm x=x++ =MOV x,tmp; INC x; MOV tmp,x
forker

3
@forker: Tôi nghĩ sẽ rõ ràng hơn nếu bạn sử dụng các hướng dẫn lắp ráp áp dụng cho bộ xử lý mà Michael đang sử dụng;)
Carl

258

Tuyên bố:

x = x++;

tương đương với:

tmp = x;   // ... this is capturing the value of "x++"
x = x + 1; // ... this is the effect of the increment operation in "x++" which
           //     happens after the value is captured.
x = tmp;   // ... this is the effect of assignment operation which is
           //     (unfortunately) clobbering the incremented value.

Tóm lại, tuyên bố không có hiệu lực.

Những điểm chính:

  • Giá trị của biểu thức tăng / giảm Postfix là giá trị của toán hạng trước khi tăng / giảm diễn ra. (Trong trường hợp biểu mẫu Tiền tố, giá trị là giá trị của toán hạng sau thao tác,)

  • RHS của biểu thức gán được đánh giá hoàn toàn (bao gồm mọi mức tăng, giảm và / hoặc các tác dụng phụ khác) trước khi giá trị được gán cho LHS.

Lưu ý rằng không giống như C và C ++, thứ tự đánh giá biểu thức trong Java hoàn toàn được chỉ định và không có chỗ cho biến thể dành riêng cho nền tảng. Trình biên dịch chỉ được phép sắp xếp lại các hoạt động nếu điều này không thay đổi kết quả thực thi mã từ phối cảnh của luồng hiện tại. Trong trường hợp này, một trình biên dịch sẽ được phép tối ưu hóa toàn bộ câu lệnh bởi vì nó có thể được chứng minh rằng nó là không có.


Trong trường hợp nó chưa rõ ràng:

  • "x = x ++;" gần như chắc chắn là một sai lầm trong bất kỳ chương trình.
  • OP (cho câu hỏi ban đầu!) Có lẽ có nghĩa là "x ++;" thay vì "x = x ++;".
  • Các câu lệnh kết hợp tự động giảm / giảm và gán trên cùng một biến là khó hiểu, và do đó nên tránh bất kể tính chính xác của chúng . Đơn giản là không cần phải viết mã như thế.

Hy vọng rằng, những người kiểm tra mã như FindBugs và PMD sẽ đánh dấu mã như thế này là đáng ngờ.


7
Như một lưu ý phụ, OP, có lẽ bạn chỉ muốn nói x++thay vì x = x++.
Jon Newmuis

3
Đúng, nhưng có lẽ nhấn mạnh rằng thặng dư xảy ra bài đánh giá bên phải biểu hiện, nhưng trước giao cho phía bên tay trái, vì thế mà rõ ràng "ghi đè"
Bohemian

2
có vẻ như là một trong những cặp sinh viên lập trình cấp ba đó ... thật tốt để làm sáng tỏ những điều cơ bản của bạn!
kumarharsh

1
@Alberto - Thật tốt khi biết rằng bạn không lấy những tuyên bố "chuyên gia" là "sự thật phúc âm". Tuy nhiên, một cách tốt hơn để xác nhận những gì tôi đã nói sẽ là tham khảo JLS. Kiểm tra biên dịch / dịch ngược của bạn chỉ cho thấy rằng những gì tôi nói là hợp lệ cho một trình biên dịch Java. Những người khác có thể (giả thiết) hành xử khác đi ... ngoại trừ việc JLS không cho phép điều đó.
Stephen C

4
Chỉ là một FYI: điều này ban đầu được đăng lên một câu hỏi khác, được đóng lại như một bản sao của câu hỏi này và hiện đã được hợp nhất.
Shog9

33
int x = 7;
x = x++;

Nó có hành vi không xác định trong C và cho Java xem câu trả lời này . Nó phụ thuộc vào trình biên dịch những gì xảy ra.


4
Không, nó không phụ thuộc vào trình biên dịch theo câu trả lời bạn đã trích dẫn - vui lòng chỉnh sửa - -1 ngay bây giờ
Mr_and_Mrs_D

@Mr_and_Mrs_D Sau đó, nó phụ thuộc vào cái gì?
Mac

2
Đó là hành vi không xác định_only cho C_. Ngay cả khi nói rằng nó phụ thuộc vào trình biên dịch là sai lệch - nó ngụ ý trình biên dịch nên chỉ định loại hành vi này. Tôi hoàn nguyên phiếu bầu của mình nhưng xem xét chỉnh sửa câu trả lời của bạn - chỉnh sửa: rất tiếc tôi không thể - bạn phải chỉnh sửa trước: D
Mr_and_Mrs_D

16

Cấu trúc như x = x++;thể hiện bạn có thể hiểu sai những gì người ++vận hành làm:

// original code
int x = 7;
x = x++;

Hãy viết lại điều này để làm điều tương tự, dựa trên việc loại bỏ ++toán tử:

// behaves the same as the original code
int x = 7;
int tmp = x; // value of tmp here is 7
x = x + 1; // x temporarily equals 8 (this is the evaluation of ++)
x = tmp; // oops! we overwrote y with 7

Bây giờ, hãy viết lại để làm (những gì tôi nghĩ) bạn muốn:

// original code
int x = 7;
x++;

Sự tinh tế ở đây là ++toán tử sửa đổi biếnx , không giống như một biểu thức x + x, như sẽ đánh giá một giá trị int nhưng xkhông thay đổi chính biến đó. Hãy xem xét một cấu trúc như forvòng lặp đáng kính :

for(int i = 0; i < 10; i++)
{
    System.out.println(i);
}

Thông báo i++trong đó? Đó là cùng một nhà điều hành. Chúng ta có thể viết lại forvòng lặp này như thế này và nó sẽ hoạt động giống nhau:

for(int i = 0; i < 10; i = i + 1)
{
    System.out.println(i);
}

Tôi cũng khuyên bạn không nên sử dụng ++toán tử trong các biểu thức lớn hơn trong hầu hết các trường hợp. Do sự tinh tế khi nó sửa đổi biến ban đầu theo mức tăng trước so với sau tăng ( ++xx++, tương ứng), nên rất dễ đưa ra các lỗi tinh vi rất khó theo dõi.


13

Theo mã Byte thu được từ các tệp lớp,

Cả hai bài tập tăng x, nhưng sự khác biệt là thời gian của when the value is pushed onto the stack

Trong Case1, Đẩy xảy ra (và sau đó được gán) trước khi tăng (về cơ bản có nghĩa là gia số của bạn không làm gì cả)

Trong Case2, Tăng xảy ra đầu tiên (làm cho nó 8) và sau đó được đẩy lên ngăn xếp (và sau đó được gán cho x)

Trường hợp 1:

int x=7;
x=x++;

Mã byte:

0  bipush 7     //Push 7 onto  stack
2  istore_1 [x] //Pop  7 and store in x
3  iload_1  [x] //Push 7 onto stack
4  iinc 1 1 [x] //Increment x by 1 (x=8)
7  istore_1 [x] //Pop 7 and store in x
8  return       //x now has 7

Trường hợp 2:

int x=7; 
x=++x;

Mã byte

0  bipush 7     //Push 7 onto stack
2  istore_1 [x] //Pop 7 and store in x
3  iinc 1 1 [x] //Increment x by 1 (x=8)
6  iload_1  [x] //Push x onto stack
7  istore_1 [x] //Pop 8 and store in x
8  return       //x now has 8
  • Stack ở đây đề cập đến Toán tử Stack, local: x index: 1 type: int

Bạn có thể vui lòng giải thích chi tiết câu trả lời của bạn.
Nihar

Xin hãy xem liên kết và bình luận được tham khảo
ngay cả

8

Nó tăng lên sau " x = x++;". Sẽ là 8 nếu bạn làm " x = ++x;".


4
Nếu nó được tăng lên sau x = x++đó, thì nó sẽ là 8.
R. Martinho Fernandes

8

Toán tử Post Post hoạt động như sau:

  1. Lưu trữ giá trị trước đó của toán hạng.
  2. Tăng giá trị của toán hạng.
  3. Trả về giá trị trước đó của toán hạng.

Vì vậy, tuyên bố

int x = 7;
x = x++; 

sẽ được đánh giá như sau:

  1. x được khởi tạo với giá trị 7
  2. toán tử gia tăng lưu trữ giá trị trước đó của x tức là 7 để trả về.
  3. Tăng x, vì vậy bây giờ x là 8
  4. Trả về giá trị trước đó của x tức là 7 và nó được gán lại cho x, do đó x lại trở thành 7

Vì vậy, x thực sự tăng nhưng vì x ++ đang gán kết quả cho x nên giá trị của x bị ghi đè lên giá trị trước đó.


Nhưng trong msvc x là 8. Có trong gcc và clang x là 7.
Mùa hè CN

7

Gia số xảy ra sau khi x được gọi, vì vậy x vẫn bằng 7. ++ x sẽ bằng 8 khi x được gọi


7

Khi bạn gán lại giá trị cho xnó vẫn là 7. Hãy thử x = ++xvà bạn sẽ nhận được 8 cái khác làm

x++; // don't re-assign, just increment
System.out.println(x); // prints 8

6

bởi vì x ++ tăng giá trị SAU khi gán nó cho biến. và trong quá trình thực hiện dòng này:

x++;

varialbe x vẫn sẽ có giá trị ban đầu (7), nhưng sử dụng lại x trên một dòng khác, chẳng hạn như

System.out.println(x + "");

sẽ cung cấp cho bạn 8.

nếu bạn muốn sử dụng giá trị tăng của x trên câu lệnh gán của mình, hãy sử dụng

++x;

Điều này sẽ tăng x thêm 1, THEN gán giá trị đó cho biến x.

[Chỉnh sửa] thay vì x = x ++, đó chỉ là x ++; cái trước gán giá trị ban đầu của x cho chính nó, vì vậy nó thực sự không làm gì trên dòng đó.


Một trong đó nói rằng nó tăng sau khi gán, và một trong đó nói rằng nó sẽ in 8. Nó tăng trước khi gán, và nó in 7.
R. Martinho Fernandes

nếu x ban đầu là 7, System.out.println (String.valueOf (x ++)); in 7. bạn có chắc chúng ta đang nói về cùng một ngôn ngữ lập trình?
josephus

Vâng là tôi. Đây ideone.com/kj2UU không in 8, giống như câu trả lời khẳng định này.
R. Martinho Fernandes

vâng, tôi đã sai x = x ++ sẽ gán 7 cho x trước khi tăng x. vì x ++ (bản thân nó là một phép gán) giải quyết trước x = (bất cứ thứ gì), giá trị được gán cho x trong x = (bất cứ thứ gì) sẽ theo sau. xin lỗi tôi đã không nhìn thấy điều đó
josephus

1
Trên thực tế, sự gia tăng là điều đầu tiên xảy ra. ideone.com/xOIDU
R. Martinho Fernandes

4

Điều gì xảy ra khi int x = 7; x = x++;nào?

ans -> x++có nghĩa là giá trị sử dụng đầu tiên của x cho biểu thức và sau đó tăng nó lên 1.
Đây là những gì xảy ra trong trường hợp của bạn. Giá trị của x trên RHS được sao chép vào biến x trên LHS và sau đó giá trị của xđược tăng thêm 1.

Tương tự ++x có nghĩa là ->tăng giá trị của x trước một và sau đó sử dụng trong biểu thức.
Vì vậy, trong trường hợp của bạn nếu bạn làm, x = ++x ; // where x = 7
bạn sẽ nhận được giá trị 8.

Để rõ ràng hơn, hãy thử tìm hiểu có bao nhiêu câu lệnh printf sẽ thực thi đoạn mã sau

while(i++ <5)   
  printf("%d" , ++i);   // This might clear your concept upto  great extend

không đúng "Giá trị của x trên RHS được sao chép vào biến x trên LHS và sau đó giá trị của x được tăng thêm 1" - điều này sẽ xlà 8, nhưng đó là 7 - gia tăng xảy ra giữa đọc và gán
user85421

3

++xđược pre-increment ->x được tăng lên trước khi được sử dụng
x++là hậu increment ->x được tăng lên sau khi được sử dụng

int x = 7; -> x get 7 value <br>
x = x++; -> x get x value AND only then x is incremented

1

Vì vậy, điều này có nghĩa là: x++không bằngx = x+1

bởi vì:

int x = 7; x = x++;
x is 7

int x = 7; x = x = x+1;
x is 8

và bây giờ có vẻ hơi lạ:

int x = 7; x = x+=1;
x is 8

rất phụ thuộc trình biên dịch!


2
Ai nói nó bằng nhau ở vị trí đầu tiên?
fortran

1
Nếu tôi là bạn, tôi sẽ bỏ ngay những cuốn sách này xD Trong mọi trường hợp, nó sẽ giống như (x = x + 1, x-1)trong C, nơi các biểu thức được phân tách bằng dấu phẩy được cho phép.
fortran

3
@fortran: Chà, trong bản sao thập kỷ của tôi "Ngôn ngữ lập trình Java, Ấn bản thứ ba" trên trang 158 có ghi "" Biểu thức i ++ tương đương với i = i + 1 ngoại trừ việc tôi chỉ được đánh giá một lần ". Nó ở vị trí đầu tiên? James Gosling, nó sẽ xuất hiện. Phần này của phiên bản Java này rất mơ hồ và được chỉ định kém; Tôi cho rằng các phiên bản sau này đã làm sạch ngôn ngữ để diễn đạt ngữ nghĩa toán tử thực tế rõ ràng hơn.
Eric Lippert

2
@fortran: bởi "ngoại trừ tôi chỉ được đánh giá một lần", tiêu chuẩn đang cố gắng truyền đạt một biểu thức như "M (). x ++" chỉ gọi M () một lần. Một từ ngữ ít mơ hồ và chính xác hơn sẽ nhấn mạnh rằng có một sự khác biệt giữa việc đánh giá i là một biến để xác định vị trí lưu trữ của nó - nghĩa là "chỉ đánh giá một lần" ở đây - và đọc hoặc ghi vào vị trí lưu trữ đó - - một trong số đó có thể là một cách giải thích hợp lý nhưng không chính xác về 'đánh giá'. Rõ ràng vị trí lưu trữ phải được đọc và viết!
Eric Lippert

1
"rất phụ thuộc vào trình biên dịch" - Không hề!
Stephen C

-1

x = x ++;

Đây là toán tử tăng sau. Nó nên được hiểu là "Sử dụng giá trị của toán hạng và sau đó tăng toán hạng".

Nếu bạn muốn điều ngược lại xảy ra, tức là "Tăng toán hạng và sau đó sử dụng giá trị của toán hạng", bạn phải sử dụng toán tử tăng trước như dưới đây.

x = ++ x;

Toán tử này trước tiên tăng giá trị của x lên 1 và sau đó gán giá trị lại cho x.


-1

Tôi nghĩ rằng tranh cãi này có thể được giải quyết mà không cần đi sâu vào mã & chỉ cần suy nghĩ.

Hãy coi i ++ & ++ i là các hàm, giả sử Func1 & Func2.

Bây giờ tôi = 7;
Func1 (i ++) trả về 7, Func2 (++ i) trả về 8 (mọi người đều biết điều này). Bên trong cả hai hàm tăng i lên 8, nhưng chúng trả về các giá trị khác nhau.

Vì vậy, i = i ++ gọi hàm Func1. Bên trong hàm i tăng lên 8, nhưng khi hoàn thành, hàm trả về 7.

Vì vậy, cuối cùng 7 được phân bổ cho i. (Vì vậy, cuối cùng, i = 7)


2
Không có "tranh cãi" hợp lệ ở đây. Mã này được trình diễn xử trong một cách đặc biệt, và chiếu theo hành vi để JLS. Bất cứ ai nghĩ rằng nó cư xử khác nhau hoặc đã không thử nó, hoặc họ bị lừa dối. (Điều này hơi giống như nói rằng 7 x 7 là 49 là "gây tranh cãi" khi ai đó quên bảng thời gian của họ ...)
Stephen C

-2

Điều này là do bạn đã sử dụng một toán tử tăng sau. Trong dòng mã sau đây

x = x++;

Điều gì xảy ra là, bạn đang gán giá trị của x cho x. x ++ tăng x sau khi giá trị của x được gán cho x. Đó là cách các toán tử tăng sau làm việc. Họ làm việc sau khi một tuyên bố đã được thực thi. Vì vậy, trong mã của bạn, x được trả về trước sau đó tăng dần.

Nếu bạn đã làm

x = ++x;

Câu trả lời sẽ là 8 vì bạn đã sử dụng toán tử tăng trước. Điều này làm tăng giá trị trước khi trả về giá trị của x.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.