Điều gì làm cho các nhà phát triển C rất tò mò nếu như i i i = = ++ [đóng cửa]


14

Chỉ là một quan sát ngẫu nhiên, dường như trên StackOverflow.com, có câu hỏi về việc nếu "++ i == i ++". Câu hỏi đó được hỏi mọi lúc, tôi nghĩ rằng tôi đã thấy nó hỏi khoảng 6 hoặc 7 lần trong 2 tháng qua.

Tôi chỉ tự hỏi tại sao các nhà phát triển C rất quan tâm đến nó? Cũng có khái niệm / câu hỏi tương tự cho các nhà phát triển C # và Java, nhưng tôi nghĩ rằng tôi chỉ thấy một câu hỏi liên quan đến C #.

Có phải vì rất nhiều ví dụ sử dụng ++ i? Có phải vì có một số cuốn sách phổ biến hoặc hướng dẫn? Có phải vì các nhà phát triển C chỉ thích nhồi nhét càng nhiều càng tốt vào một dòng duy nhất để 'hiệu quả' / 'hiệu suất' và do đó gặp phải các cấu trúc 'lạ' khi sử dụng toán tử ++ thường xuyên hơn?


23
(Đối với tôi là nhà phát triển C #, i ++ và ++ tôi bằng nhau về điều đó, nhưng với tư cách là một nhà phát triển C #, tôi không cố lưu một hoặc hai chu kỳ đồng hồ vì dù sao tôi cũng tương đối kém hiệu quả)
Michael Stum

1
là những lập trình viên vừa chớm nở, chúng tôi thích chơi với số học, logic và tò mò về cách mọi thứ hoạt động. Tôi nghĩ đó là một lý do lớn mà chúng tôi yêu thích những câu hỏi như vậy. nó có thể không phải là một tính năng phá vỡ nhưng nó chắc chắn là thú vị! Không phải đó là lý do chúng tôi trở thành lập trình viên ngay từ đầu sao?!
Chani

2
Bạn có nghĩa đen là nói đến biểu thức ++i == i++, hay nói chung hơn về sự khác biệt về ý nghĩa giữa ++ii++?
Keith Thompson

Câu trả lời:


30

Tôi nghi ngờ rằng ít nhất một phần của nó đơn giản hơn một chút: ngay cả bây giờ, chúng ta cũng thấy rất nhiều câu hỏi như thế này bắt đầu vào khoảng đầu năm học, và chúng dần dần giảm dần trong suốt cả năm.

Như vậy, tôi nghĩ thật công bằng khi đoán rằng khá nhiều trong số chúng chỉ đơn giản là kết quả của các lớp học mà giáo viên nói ít nhất một chút về nó, nhưng không giải thích rõ (các) quan điểm của mình (thường là không bởi vì anh ta không thực sự hiểu họ). Đặc biệt dựa trên những người dường như hỏi những câu hỏi này, rất ít người dựa trên mã hóa thực tế.


14
Đây không phải là trái ngược với Tháng Chín vĩnh cửu sao? Tháng 9 vĩnh cửu là khi AOL bắt đầu cung cấp quyền truy cập Usenet cho khách hàng của họ, làm cho nó giống như tháng 9 (tháng mà học sinh mới bắt đầu đi học truyền thống bắn phá các bảng như người mới) quanh năm.
nlawalker

Đó là một lý thuyết thú vị nhưng có lẽ không phải lúc nào cũng là lỗi của giáo viên nếu ai đó không hiểu tài liệu: có thể các sinh viên (1) không chú ý đầy đủ trong giờ học và (2) quá lười biếng để tìm câu trả lời về stackoverflow trước hỏi cùng một câu hỏi một lần nữa
Giorgio

12

Bởi vì các lập trình viên C CÓ để hiểu thứ tự các hoạt động. Các nhà phát triển C # không nhất thiết phải sử dụng các toán tử bitwise (&, |, ~) hoặc các toán tử tiền tố vì chúng ta thường lo lắng hơn về các thứ khác. Tuy nhiên, điều mà các nhà phát triển C # của chúng tôi không nhận ra là chúng ta nên biết những gì các nhà khai thác chúng ta sử dụng hàng ngày làm gì và làm thế nào để sử dụng chúng đúng cách. Hầu hết chúng ta chỉ tránh những nơi có thể là một vấn đề.

Nằm trên đỉnh đầu của bạn, đầu ra của đoạn trích này là gì?

    double x = 5.5;
    Console.WriteLine(x++);
    x = 5.5;
    Console.WriteLine(++x);

Tôi có thể nói rằng một số lượng lớn các nhà phát triển C # dày dạn không biết đầu ra của Console là gì.


3
+1. Biết được sự khác biệt giữa các toán tử tăng / giảm trước sửa lỗi là đáng giá cho các tình huống như thế này.
Maulrus

4
Tôi cũng thấy được vấn đề và tôi cũng không biết đầu ra (tôi tin đó là 5.5 và 6.5, nhưng tôi không chắc), và đối với tôi nó không quan trọng vì tôi sẽ tái cấu trúc nó thành x ++; Bảng điều khiển.WriteLine (x); ngay. Tôi không hoàn toàn không biết gì, tuy nhiên, tôi chỉ nghĩ rằng đó là một mùi mã lớn với khả năng sử dụng bằng không.
Michael Stum

8
Câu trả lời cho câu hỏi không liên quan gì đến thứ tự các thao tác, hoặc sự khác biệt giữa gia tăng tiền tố và hậu tố. Đó là một vấn đề của hành vi được xác định và không xác định.
David Thornley

2
Tôi đã gặp điều này ngày hôm nay. Một cái gì đó như if (myList[i++] == item). Tài giỏi. Tôi thấy nó đang tìm kiếm nguồn gốc của một ngoại lệ IndexOutOfRange ... Thật vậy, rất "thông minh".
rmac

6
Tôi nghĩ đó là 5.5 và 6.5, nhưng tôi chưa bao giờ thấy ++được sử dụng trên phao trước đây và tôi phải nói rằng nó không cảm thấy rất phù hợp. Mọi người có làm vậy không? (Tôi thích += 1)
Bart van Heukelom

8

Tôi nghĩ rằng điều này là rõ ràng. Trong C #, đối với int i, i++ == ++iluôn luôn sai trong khi ++i == i++luôn luôn đúng, đáng tin cậy và mọi người quan tâm có thể dễ dàng tìm thấy điều này chỉ bằng cách tìm hiểu các quy tắc của C # (hoặc thực sự chỉ bằng cách chạy nó).

Mặt khác, trong C và C ++, nó gần như không được xác định bởi vì nó phụ thuộc vào trình biên dịch, môi trường thực thi, nền tảng, v.v., vì vậy đây là một câu hỏi khó trả lời hơn, vì vậy rất nhiều người hỏi nó.


+1 - nhưng đó không thực sự là một câu hỏi khó trả lời. "Không xác định" là một từ. Tất cả những thứ "nó phụ thuộc vào ..." là thứ mà hầu hết mọi người không lo lắng. Ngay cả khi bạn chỉ viết cho một nền tảng cụ thể, bạn vẫn nên sử dụng toàn bộ thành ngữ thông thường cho ngôn ngữ và hầu hết việc sử dụng các toán tử tăng trước và tăng sau là một phần của một vài thành ngữ phổ biến.
Steve314

+1: Điều này thực sự trả lời câu hỏi được hỏi (nghĩa là bạn không đọc giữa các dòng).
Thomas Eding

5

Rất có thể bởi vì trong C, nó thực sự quan trọng nếu bạn viết i++hoặc ++ikhi bạn đang thực hiện số học con trỏ. Ở đó, tăng itrước hoặc sau một hoạt động có thể rất quan trọng. Tôi sẽ cho bạn một ví dụ nhưng lần cuối cùng tôi viết C là 10 năm trước ...

Trong C #, tôi chưa bao giờ gặp phải một tình huống đòi hỏi tôi phải suy nghĩ i++hoặc ++ivì AFAIK, đối với các vòng lặp for / while, điều đó không thực sự quan trọng.


3
Điều quan trọng là phải hiểu sự khác biệt trong C # - chỉ vì bạn dường như chỉ sử dụng chúng cho / mỗi vòng lặp không có nghĩa đó là nơi duy nhất bạn sẽ tìm thấy chúng
STW

hoàn toàn đúng sự thật
Mladen Prajdic

3
Điều này không liên quan đến câu hỏi. Câu hỏi không phải là về sự khác biệt giữa i++++i, nhưng kết hợp chúng trong cùng một biểu thức.
David Thornley

@David Câu hỏi là tại sao các lập trình viên C tò mò về nó. Câu trả lời (Vấn đề ở C, không quá nhiều trong C #) là hoàn toàn phù hợp ".
Florian F

4

Đó là một câu hỏi phổ biến vì đó là một câu hỏi mẹo. Nó không được xác định .

Liên kết ở trên đi đến Câu hỏi thường gặp trên trang chủ của Bjarnes Stroustrup, giải quyết cụ thể câu hỏi này và giải thích lý do tại sao cấu trúc này không được xác định. Những gì nó nói là:

Về cơ bản, trong C và C ++, nếu bạn đọc một biến hai lần trong một biểu thức mà bạn cũng viết nó, kết quả là không xác định.

Có thứ tự đánh giá không xác định được tuyên bố để mang lại mã hiệu suất tốt hơn.


2

Vài năm trước tôi đọc được rằng các nhà khai thác này được coi là nguy hiểm nên tôi đã cố gắng đào thêm thông tin về nó. Nếu stackoverflow đã lên vào thời điểm đó, tôi sẽ hỏi nó ở đó.

Bây giờ là bởi vì một số người xoắn viết vòng lặp như

while( [something] )
{
  a[++j] = ++j;
}

Ngay cả bây giờ, tôi không chắc chắn về những gì sẽ / sẽ xảy ra, nhưng với tôi khá rõ ràng rằng nhiều ++ [var] trên cùng một dòng đang yêu cầu sự cố.


2
Các phần tăng có hành vi không xác định là một phần của bài tập trong C
tzenes

7
Các bài tập như x = ++j;được xác định rõ trong C. Phần trên không được xác định vì jđược sửa đổi hai lần mà không có điểm trình tự can thiệp.
Matthew Flaschen

2

Hai lý do.

Việc thực hiện chính xác của ++ i là tăng i và sau đó trả lại. Việc thực hiện đúng của i ++ là lưu giá trị hiện tại, tăng i và trả về giá trị đã lưu. Biết những điều này không được thực hiện như các từ đồng nghĩa là quan trọng.

Câu hỏi sau đó trở thành khi trình biên dịch áp dụng chúng trong khi đánh giá một biểu thức, chẳng hạn như đẳng thức.

Nếu kiểm tra đẳng thức được thực hiện trước, thì các toán tử tăng trước và sau tăng, bạn sẽ phải viết logic khác với nếu phía bên trái (lhs) và phía bên phải (rhs) được đánh giá trước, sau đó sự bình đẳng

Đó là tất cả về thứ tự của các hoạt động, và điều đó ảnh hưởng đến mã người viết. Và, không quá ngạc nhiên, không phải tất cả các ngôn ngữ đều đồng ý.

Các kiểm tra cơ bản liệt kê điều này cho phép các nhà phát triển kiểm tra xem liệu các giả định của họ có đúng không, cũng như liệu việc triển khai thực tế có phù hợp với đặc tả ngôn ngữ hay không.

Điều này có thể có tất cả các loại tác động khi làm việc với con trỏ, vòng lặp hoặc trả về giá trị.


5
Các xét nghiệm cơ bản về điều này sẽ gây hiểu nhầm, bởi vì đó là hành vi không xác định. Nếu nó hoạt động chính xác như bạn mong đợi lần này, không có gì đảm bảo nó sẽ diễn ra vào lần tới.
David Thornley

Bạn đã trả lời sai câu hỏi. Bạn nên trả lời tại sao lập trình viên C tò mò về nó.
Hugo

Para thứ hai của bạn dù sao cũng không chính xác (ít nhất là trước C ++ 11): hành vi của ++isử dụng giá trịi+1tại một thời điểm nào đó, có thể trước hoặc sau đó, nhưng trước điểm tiếp theo, tăng dầni .
MM

@MattMcNabb - Bạn có thể chỉ cho tôi một đặc điểm kỹ thuật cho điều đó không, tôi tò mò muốn tìm hiểu nếu mọi thứ đã thay đổi khi thực hiện. Quay trở lại những ngày mà C ánh xạ độc đáo vào lắp ráp PDP, ++ i đã đưa ra một lệnh INC, trong khi phiên bản hậu tố phải sao chép giá trị trong một thanh ghi để sử dụng một lệnh sau khi tăng. Điều gì tạo nên sự cần thiết cho sự thay đổi mà bạn mô tả?
Walt Stoneburner

2

Tôi nghĩ đó là một điều sốc văn hóa.

Như đã chỉ ra, hành vi của một biểu thức trong C hoặc C ++ có thể không được xác định bởi vì thứ tự thực hiện của các mức tăng sau vv không được xác định nghiêm ngặt. Hành vi không xác định là khá phổ biến trong C, và tất nhiên rất nhiều trong số đó đã được nhập vào C ++.

Đối với một người đã thực hiện một số chương trình bằng ngôn ngữ khác - một người đã đưa ra ý tưởng rằng các ngôn ngữ lập trình được cho là chính xác, và các máy tính được cho là làm những gì họ bảo phải làm ... tốt, đó là một cú sốc đối với phát hiện ra rằng C đang mơ hồ về một số điều.


C là theo cách này bởi vì nó được thiết kế để hỗ trợ nhiều nền tảng hơn cả khi C # được xác định, bao gồm các nền tảng nhúng hoặc máy tính lớn kỳ lạ nhất mà bạn có thể nghĩ đến. C #, mặt khác, chạy trên ... x86 và 360? có lẽ ARM cũng vậy? Không có gì khác. Đó là lý do tại sao C # có thể định nghĩa nhiều hơn nữa.
DeadMG

++ Ngoài ra, không phải C lần đầu tiên được xây dựng trên PDP-11? Trường hợp đã có hướng dẫn tăng tự động? C muốn được "gần với máy" để nó có thể sử dụng tập lệnh một cách hữu ích.
Mike Dunlavey

@MikeDunlavey: Không, C ++và các --nhà khai thác không dựa trên PDP-11, không tồn tại khi các toán tử đó được giới thiệu bằng ngôn ngữ tiền thân của C B. Xem cm.bell-labs.com/who/dmr/chist.html , và tìm kiếm "tự động tăng".
Keith Thompson

1

Có lẽ nói chung là các nhà phát triển C sử dụng gia tăng ++ thường xuyên hơn - xem như cách C không có "foreach" hoặc câu lệnh tương tự để lặp qua các mảng. Oh, và tất nhiên con trỏ arithmatic, như đã đề cập trước đây!


1
Điểm hay, quên rằng foreach là một khái niệm tương đối hiện đại.
Michael Stum

-1

Sự khác biệt giữa cả hai phần: bài đăng và phần trước đang hoạt động theo cách hai phần mã này sẽ hoạt động trong mọi ngôn ngữ. ĐÂY KHÔNG PHẢI LÀ NGƯỜI PHỤ THUỘC NGÔN NGỮ !!!

++i

Đây là gia tăng trước. Đoạn mã này trước tiên sẽ tăng giá trị itrước khi nó gửi giá trị đến dòng nơi nó được sử dụng.

i++

Đây là sự gia tăng bài. Đoạn mã này sẽ trả về giá trị itrước khi nó tăng giá trị của idòng nơi nó được sử dụng.

Trong một ví dụ nhỏ khác:

int main(void)
{
  int i = 0; 
  int result; 
  result = 10 + ++i; 
  printf("%d \n", result); // = 11 

  int j = 0; 
  result = 10 + j++; 
  printf("%d \n", result);// = 10
  return 0;
}

Mã này biên dịch với kết quả trên codepad.

Điều này phải làm với việc thực hiện nội bộ của quá tải toán tử.

++i tăng trực tiếp giá trị (và do đó nhanh hơn một chút)

i++đầu tiên tạo một bản sao được trả về nơi cần thiết và sau đó giá trị ban đầu của ibiến được tăng thêm một.

Tôi hy vọng điều này là rõ ràng bây giờ.


Tuy nhiên, điều này không đáp ứng câu hỏi thực tế: tại sao các nhà phát triển C hỏi về điều này nhiều hơn những người khác. OP hiểu các nhà khai thác.
Martijn Pieters

Ngoài ra câu trả lời này là thực tế không chính xác. ++ikhông nhanh hơn và i++không tạo bản sao. Hơn nữa, ++ihành vi hơi khác nhau trong C so với C ++, nói gì đến giữa các ngôn ngữ khác.
MM
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.