Tại sao x = x ++ không xác định?


19

Nó không được xác định bởi vì nó sửa đổi xhai lần giữa các điểm chuỗi. Tiêu chuẩn nói rằng nó không được xác định, do đó nó không được xác định.
Điều đó nhiều tôi biết.

Nhưng tại sao?

Hiểu biết của tôi là việc cấm điều này cho phép trình biên dịch tối ưu hóa tốt hơn. Điều này có thể có ý nghĩa khi C được phát minh, nhưng bây giờ có vẻ như là một đối số yếu.
Nếu chúng ta tái tạo C ngày hôm nay, chúng ta sẽ làm theo cách này, hay nó có thể được thực hiện tốt hơn?
Hoặc có thể có một vấn đề sâu sắc hơn, khiến cho việc xác định các quy tắc nhất quán cho các biểu thức đó trở nên khó khăn hơn, vì vậy tốt nhất là cấm chúng?

Vì vậy, giả sử chúng tôi đã phát minh lại C ngày hôm nay. Tôi muốn đề xuất các quy tắc đơn giản cho các biểu thức như x=x++, dường như tôi làm việc tốt hơn các quy tắc hiện có.
Tôi muốn biết ý kiến ​​của bạn về các quy tắc được đề xuất so với các quy tắc hiện có hoặc các đề xuất khác.

Quy tắc đề xuất:

  1. Giữa các điểm trình tự, thứ tự đánh giá là không xác định.
  2. Tác dụng phụ diễn ra ngay lập tức.

Không có hành vi không xác định liên quan. Biểu thức đánh giá giá trị này hoặc giá trị đó, nhưng chắc chắn sẽ không định dạng đĩa cứng của bạn (kỳ lạ là tôi chưa bao giờ thấy một triển khai trong đó x=x++định dạng đĩa cứng).

Biểu thức ví dụ

  1. x=x++- Được xác định rõ, không thay đổi x.
    Đầu tiên, xđược tăng lên (ngay lập tức khi x++được đánh giá), sau đó giá trị cũ của nó được lưu trữ trong x.

  2. x++ + ++x- Tăng xhai lần, đánh giá 2*x+2.
    Mặc dù một trong hai bên có thể được đánh giá trước, kết quả là x + (x+2)(bên trái trước) hoặc (x+1) + (x+1)(bên phải trước).

  3. x = x + (x=3)- Không xác định, xđược đặt thành x+3hoặc 6.
    Nếu bên phải được đánh giá đầu tiên, đó là x+3. Nó cũng có thể x=3được đánh giá đầu tiên, vì vậy nó 3+3. Trong cả hai trường hợp, x=3phép gán xảy ra ngay lập tức khi x=3được ước tính, do đó giá trị được lưu trữ sẽ bị ghi đè bởi phép gán khác.

  4. x+=(x=3)- Được xác định rõ, đặt xthành 6.
    Bạn có thể lập luận rằng đây chỉ là tốc ký cho biểu thức trên.
    Nhưng tôi muốn nói rằng +=phải được thực hiện sau x=3, và không phải trong hai phần (đọc x, đánh giá x=3, thêm và lưu trữ giá trị mới).

Lợi thế là gì?

Một số ý kiến ​​nêu lên điểm tốt này.
Tôi chắc chắn không nghĩ các biểu thức như x=x++nên được sử dụng trong bất kỳ mã thông thường nào.
Trên thực tế, tôi là nhiều hơn nữa nghiêm ngặt hơn - Tôi nghĩ rằng việc sử dụng chỉ tốt cho x++trong khi x++;một mình.

Tuy nhiên, tôi nghĩ các quy tắc ngôn ngữ phải đơn giản nhất có thể. Nếu không, các lập trình viên chỉ không hiểu họ. quy tắc cấm thay đổi một biến hai lần giữa các điểm chuỗi chắc chắn là quy tắc mà hầu hết các lập trình viên không hiểu.

Một quy tắc rất cơ bản là:
Nếu A hợp lệ và B hợp lệ và chúng được kết hợp theo cách hợp lệ, kết quả là hợp lệ.
xlà giá trị L hợp lệ, x++là biểu thức hợp lệ và =là cách hợp lệ để kết hợp giá trị L và biểu thức, vậy tại sao x=x++không hợp pháp?
Tiêu chuẩn C tạo ra một ngoại lệ ở đây và ngoại lệ này làm phức tạp các quy tắc. Bạn có thể tìm kiếm stackoverflow.com và xem ngoại lệ này khiến mọi người bối rối đến mức nào.
Vì vậy, tôi nói - thoát khỏi sự nhầm lẫn này.

=== Tóm tắt câu trả lời ===

  1. Tại sao làm điều đó?
    Tôi đã cố gắng giải thích trong phần trên - tôi muốn các quy tắc C đơn giản.

  2. Tiềm năng tối ưu hóa:
    Điều này có một chút tự do từ trình biên dịch, nhưng tôi không thấy bất cứ điều gì thuyết phục tôi rằng nó có thể quan trọng.
    Hầu hết các tối ưu hóa vẫn có thể được thực hiện. Ví dụ, a=3;b=5;có thể được sắp xếp lại, mặc dù tiêu chuẩn chỉ định thứ tự. Các biểu thức như a=b[i++]vẫn có thể được tối ưu hóa tương tự.

  3. Bạn không thể thay đổi tiêu chuẩn hiện có.
    Tôi thừa nhận, tôi không thể. Tôi không bao giờ nghĩ rằng tôi thực sự có thể đi trước và thay đổi các tiêu chuẩn và trình biên dịch. Tôi chỉ muốn nghĩ nếu mọi thứ có thể được thực hiện khác đi.


10
Tại sao điều này quan trọng với bạn? Nó nên được xác định, và nếu vậy, tại sao? Không có nhiều điểm trong việc gán xcho chính nó và nếu bạn muốn tăng lên, xbạn chỉ có thể nói x++;- không cần chuyển nhượng. Tôi muốn nói rằng nó không nên được định nghĩa chỉ vì khó có thể nhớ những gì sẽ xảy ra.
Caleb

4
Trong tâm trí tôi, đây là một câu hỏi hay ("Một số người đàn ông nhìn thấy mọi thứ như họ và hỏi tại sao, tôi mơ những điều chưa từng có và hỏi tại sao không"). Đó là (theo ý kiến ​​của tôi) một câu hỏi hoàn toàn về thiết kế ngôn ngữ, sử dụng cú pháp C làm ví dụ, không phải là câu hỏi về cú pháp C. Cá nhân tôi nghĩ rằng lý do chúng ta không xác định hành vi cho các biểu thức, chẳng hạn như x ++ + ++ x hoặc x = x ++ đơn giản là vì có khả năng chúng bị đọc sai.
Jamie Taylor

5
@ugoren: Tại sao bạn cần dự đoán kết quả. Không ai trong tâm trí của họ sẽ viết mã như vậy (như đã được đề cập nhiều lần) ngay cả khi bạn đã viết mã như thế này, nó sẽ bị từ chối trong lần xem xét mã đầu tiên. Vì vậy, không cần xác định hành vi và cung cấp cho trình tối ưu hóa cơ hội tốt nhất để tối ưu hóa nó. Trong mọi ví dụ bạn đề xuất tôi sẽ bắn ai đó nếu họ thêm nó vào cơ sở mã.
Martin York

3
Tôi sẽ tìm thấy một câu hỏi thú vị hơn là tại sao không phải là một lỗi để viết này? Chắc chắn một trình biên dịch có thể phát hiện ra hành vi không xác định của nó và do đó không thể là điều người dùng thực sự muốn, vậy tại sao không có lỗi? Tôi hiểu rằng một số trường hợp của bahavour không xác định rất khó phát hiện nhưng đây không phải là
JohnB

3
" Quy tắc cấm thay đổi một biến hai lần giữa các điểm chuỗi chắc chắn là quy tắc mà hầu hết các lập trình viên không hiểu. " - Bạn có bằng chứng nào cho việc này không? Hầu hết các câu hỏi tôi đã thấy được hỏi bởi vì các lập trình viên không biết về quy tắc. Có bằng chứng nào cho thấy hầu hết họ vẫn không hiểu nó sau khi được giải thích không?
Bảo mật

Câu trả lời:


24

Có lẽ trước tiên bạn nên trả lời câu hỏi tại sao cần xác định? Có bất kỳ lợi thế nào trong phong cách lập trình, khả năng đọc, khả năng duy trì hoặc hiệu suất bằng cách cho phép các biểu thức như vậy với các tác dụng phụ bổ sung không? Là

y = x++ + ++x;

dễ đọc hơn

y = 2*x + 2;
x += 2;

Cho rằng một sự thay đổi như vậy là vô cùng cơ bản và phá vỡ cơ sở mã hiện có.


1
Tôi đã thêm một phần "tại sao" vào câu hỏi của tôi. Tôi chắc chắn không đề xuất sử dụng các biểu thức này, nhưng tôi quan tâm đến việc có các quy tắc đơn giản để nói ý nghĩa của biểu thức.
ugoren

Ngoài ra, thay đổi này không phá vỡ mã hiện có, trừ khi nó gọi hành vi không xác định. Sửa lỗi cho tôi nếu tôi sai.
ugoren

3
Vâng, một câu trả lời triết lý hơn: Hiện tại nó chưa được xác định. Nếu không có lập trình viên nào sử dụng nó, thì bạn không cần phải hiểu các biểu thức như vậy, vì không nên có bất kỳ mã nào. Nếu bạn cần hiểu chúng, thì rõ ràng phải có rất nhiều mã dựa trên hành vi không xác định. ;)
Bảo mật

1
Theo định nghĩa, nó không phá vỡ bất kỳ cơ sở mã hiện có nào để xác định các hành vi. Nếu chúng chứa UB, theo định nghĩa, chúng đã bị hỏng.
DeadMG

1
@ugoren: Phần "tại sao" của bạn vẫn không trả lời câu hỏi thực tế: tại sao bạn muốn biểu thức kỳ dị này trong mã của mình? Nếu bạn không thể đưa ra một câu trả lời thuyết phục cho điều đó, thì toàn bộ cuộc thảo luận sẽ được đưa ra.
Mike Baranczak

20

Đối số làm cho hành vi không xác định này cho phép tối ưu hóa tốt hơn không phải là yếu ngày nay. Trên thực tế, ngày nay nó mạnh hơn nhiều so với khi C còn mới.

Khi C còn mới, các máy có thể tận dụng điều này để tối ưu hóa tốt hơn chủ yếu là các mô hình lý thuyết. Mọi người đã nói về khả năng xây dựng CPU trong đó trình biên dịch sẽ hướng dẫn CPU về những hướng dẫn nào có thể / nên được thực hiện song song với các hướng dẫn khác. Họ chỉ ra thực tế rằng việc cho phép điều này có hành vi không xác định có nghĩa là trên CPU như vậy, nếu nó thực sự tồn tại, bạn có thể lên lịch cho phần "tăng" của lệnh để thực thi song song với phần còn lại của luồng lệnh. Mặc dù họ đã đúng về lý thuyết, vào thời điểm đó, có rất ít cách thức phần cứng thực sự có thể tận dụng khả năng này.

Đó không chỉ là lý thuyết nữa. Bây giờ có phần cứng trong sản xuất và được sử dụng rộng rãi, (ví dụ, Itanium, VLIW DSP) có thể thực sự tận dụng lợi thế này. Họ thực sự làm phép trình biên dịch để tạo ra một dòng lệnh mà quy định cụ thể mà hướng dẫn X, Y và Z có thể tất cả được thực hiện song song. Đây không còn là một mô hình lý thuyết - đó là phần cứng thực sự trong sử dụng thực sự làm việc thực sự.

IMO, làm cho hành vi được xác định này gần với "giải pháp" tồi tệ nhất có thể cho vấn đề. Bạn rõ ràng không nên sử dụng các biểu thức như thế này. Đối với phần lớn mã, hành vi lý tưởng sẽ là trình biên dịch đơn giản loại bỏ hoàn toàn các biểu thức đó. Vào thời điểm đó, trình biên dịch C không thực hiện phân tích dòng chảy cần thiết để phát hiện điều đó một cách đáng tin cậy. Ngay cả tại thời điểm của tiêu chuẩn C ban đầu, nó vẫn không hề phổ biến.

Tôi không chắc chắn nó sẽ được cộng đồng chấp nhận ngày hôm nay - trong khi nhiều trình biên dịch có thể thực hiện loại phân tích dòng chảy đó, họ thường chỉ làm điều đó khi bạn yêu cầu tối ưu hóa. Tôi nghi ngờ hầu hết các lập trình viên muốn ý tưởng làm chậm quá trình "gỡ lỗi" chỉ vì mục đích có thể từ chối mã mà họ (không lành mạnh) sẽ không bao giờ viết ngay từ đầu.

Những gì C đã làm là một lựa chọn tốt thứ hai bán hợp lý: bảo mọi người không làm điều đó, cho phép (nhưng không yêu cầu) trình biên dịch từ chối mã. Điều này tránh việc biên dịch chậm (vẫn còn nữa) cho những người không bao giờ sử dụng nó, nhưng vẫn cho phép ai đó viết trình biên dịch sẽ từ chối mã đó nếu họ muốn (và / hoặc có cờ sẽ từ chối mà mọi người có thể chọn sử dụng hoặc không như họ thấy phù hợp).

Ít nhất là IMO, làm cho hành vi được xác định này sẽ (ít nhất là gần với) quyết định tồi tệ nhất có thể được đưa ra. Trên phần cứng kiểu VLIW, các lựa chọn của bạn sẽ là tạo mã chậm hơn để sử dụng hợp lý các toán tử gia tăng, chỉ vì lợi ích của mã tào lao lạm dụng chúng, hoặc nếu không luôn yêu cầu phân tích dòng chảy rộng rãi để chứng minh rằng bạn không xử lý mã crappy, vì vậy bạn chỉ có thể tạo mã chậm (nối tiếp) khi thực sự cần thiết.

Điểm mấu chốt: nếu bạn muốn chữa vấn đề này, bạn nên suy nghĩ theo hướng ngược lại. Thay vì xác định những gì mã đó làm, bạn nên xác định ngôn ngữ để các biểu thức đó hoàn toàn không được phép (và sống với thực tế là hầu hết các lập trình viên có thể sẽ chọn cách biên dịch nhanh hơn khi thực thi yêu cầu đó).


IMO, có rất ít lý do để tin rằng trong hầu hết các trường hợp, các hướng dẫn chậm thực sự chậm hơn nhiều so với hướng dẫn nhanh và những điều này sẽ luôn có tác động đến hiệu suất chương trình. Tôi sẽ lớp này dưới tối ưu hóa sớm.
DeadMG

Có lẽ tôi đang thiếu một cái gì đó - nếu không ai từng viết mã như vậy, tại sao lại quan tâm đến việc tối ưu hóa nó?
ugoren

1
@ugoren: viết mã như a=b[i++];(ví dụ) là tốt, và tối ưu hóa nó là một điều tốt. Tuy nhiên, tôi không thấy điểm gây tổn thương mã hợp lý như thế chỉ để một cái gì đó giống như ++i++có ý nghĩa xác định.
Jerry Coffin

2
@ugoren Vấn đề là một trong những chẩn đoán. Mục đích duy nhất của việc không hoàn toàn không cho phép các biểu thức như ++i++chính xác là nói chung khó phân biệt chúng với các biểu thức hợp lệ với các tác dụng phụ (chẳng hạn như a=b[i++]). Nó có vẻ đủ đơn giản đối với chúng tôi, nếu tôi nhớ chính xác Sách Rồng thì đó thực sự là một vấn đề khó khăn. Đó là lý do tại sao hành vi này là UB, chứ không phải bị cấm.
Konrad Rudolph

1
Tôi không tin rằng hiệu suất là một đối số hợp lệ. Tôi đấu tranh để tin rằng trường hợp này là đủ phổ biến, xem xét sự khác biệt rất nhỏ và thực hiện rất nhanh trong cả hai trường hợp, cho một sự sụt giảm hiệu suất nhỏ là đáng chú ý - không đề cập đến trên nhiều bộ xử lý và kiến ​​trúc, xác định nó là miễn phí.
DeadMG

9

Eric Lippert, một nhà thiết kế chính trong nhóm trình biên dịch C #, đã đăng trên blog của mình một bài viết về một số cân nhắc đi vào việc chọn làm cho một tính năng không xác định ở cấp độ ngôn ngữ. Rõ ràng C # là một ngôn ngữ khác, với các yếu tố khác nhau đi vào thiết kế ngôn ngữ của nó, tuy nhiên những điểm anh ấy đưa ra có liên quan.

Cụ thể, ông chỉ ra vấn đề có các trình biên dịch hiện có cho một ngôn ngữ có triển khai hiện có và cũng có đại diện trong một ủy ban. Tôi không chắc đó có phải là trường hợp ở đây không, nhưng có xu hướng phù hợp với hầu hết các cuộc thảo luận về thông số kỹ thuật liên quan đến C và C ++.

Cũng cần lưu ý là, như bạn đã nói, tiềm năng hiệu suất để tối ưu hóa trình biên dịch. Mặc dù sự thật là hiệu năng của CPU ngày nay lớn hơn nhiều so với khi C còn trẻ, một lượng lớn lập trình C được thực hiện ngày nay được thực hiện cụ thể vì khả năng tăng hiệu suất và tiềm năng (tương lai giả định ) Tối ưu hóa lệnh CPU và tối ưu hóa xử lý đa lõi sẽ là điều ngớ ngẩn để ngăn chặn vì một bộ quy tắc quá hạn chế để xử lý các hiệu ứng phụ và các điểm chuỗi.


Từ bài viết bạn liên kết đến, có vẻ như C # không khác xa với những gì tôi đề xuất. Thứ tự các tác dụng phụ được định nghĩa "khi quan sát từ luồng gây ra tác dụng phụ". Tôi đã không đề cập đến đa luồng, nhưng nói chung C không đảm bảo nhiều cho một người quan sát trong một luồng khác.
ugoren

5

Đầu tiên, chúng ta hãy xem định nghĩa của hành vi không xác định:

3.4.3

1 hành
vi chưa được thực hiện, khi sử dụng cấu trúc chương trình không thể truy cập được hoặc có lỗi hoặc dữ liệu sai, theo Tiêu chuẩn quốc tế này không áp dụng bất kỳ yêu cầu nào

2 LƯU Ý một đặc điểm cách thức được ghi lại của môi trường (có hoặc không có thông báo chẩn đoán), để chấm dứt dịch thuật hoặc thực thi (với việc phát hành thông báo chẩn đoán).

3 VÍ DỤ Một ví dụ về hành vi chưa hoàn thành là hành vi trên số nguyên trên fl ow

Vì vậy, nói cách khác, "hành vi không xác định" đơn giản có nghĩa là trình biên dịch có thể tự do xử lý tình huống theo bất kỳ cách nào nó muốn và bất kỳ hành động nào như vậy đều được coi là "chính xác".

Nguồn gốc của vấn đề đang thảo luận là mệnh đề sau:

6.5 Biểu thức

...
3 Việc nhóm các toán tử và toán hạng được biểu thị bằng cú pháp. 74) Trừ khi Speci fi ed hơn (dành cho chức năng gọi (), &&, ||, ?:, và các nhà khai thác dấu phẩy), trình tự thẩm định subexpressions và thứ tự mà tác dụng phụ xảy ra đều fi ed unspeci .

Nhấn mạnh thêm.

Đưa ra một biểu thức như

x = a++ * --b / (c + ++d);

các subexpressions a++, --b, c, và ++dcó thể được đánh giá theo thứ tự nào . Hơn nữa, các tác dụng phụ của a++, --b++dcó thể được áp dụng tại bất kỳ thời điểm nào trước điểm tiếp theo tiếp theo (IOW, ngay cả khi a++được đánh giá trước --b, nó không được đảm bảo asẽ được cập nhật trước khi --bđược đánh giá). Giống như những người khác đã nói, lý do căn bản của hành vi này là cho phép thực hiện tự do sắp xếp lại các hoạt động một cách tối ưu.

Do đó, tuy nhiên, các biểu thức như

x = x++
y = i++ * i++
a[i] = i++
*p++ = -*p    // this one bit me just yesterday

v.v., sẽ mang lại kết quả khác nhau cho các triển khai khác nhau (hoặc cho cùng một triển khai với các cài đặt tối ưu hóa khác nhau hoặc dựa trên mã xung quanh, v.v.).

Hành vi này không được xác định để trình biên dịch không có nghĩa vụ "làm điều đúng", bất cứ điều gì có thể. Các trường hợp trên là đủ dễ dàng để bắt, nhưng có một số trường hợp không tầm thường sẽ khó có thể bắt được tại thời điểm biên dịch.

Rõ ràng, bạn có thể thiết kế một ngôn ngữ theo thứ tự đánh giá và thứ tự áp dụng các tác dụng phụ được xác định nghiêm ngặt và cả Java và C # đều làm như vậy, phần lớn là để tránh các vấn đề mà định nghĩa C và C ++ dẫn đến.

Vậy, tại sao thay đổi này không được thực hiện cho C sau 3 lần sửa đổi tiêu chuẩn? Trước hết, có mã C kế thừa 40 năm ngoài kia và không đảm bảo rằng một thay đổi như vậy sẽ không phá vỡ mã đó. Nó đặt một chút gánh nặng lên các nhà văn trình biên dịch, vì một sự thay đổi như vậy sẽ ngay lập tức làm cho tất cả các trình biên dịch hiện có không tuân thủ; mọi người sẽ phải viết lại đáng kể. Và ngay cả trên các CPU nhanh, hiện đại, vẫn có thể nhận ra hiệu suất thực sự bằng cách điều chỉnh thứ tự đánh giá.


1
Giải thích rất tốt về vấn đề này. Tôi không đồng ý về việc phá vỡ các ứng dụng cũ - cách thức thực hiện hành vi không xác định / không xác định đôi khi thay đổi giữa phiên bản trình biên dịch, mà không có bất kỳ thay đổi nào trong tiêu chuẩn. Tôi không đề nghị thay đổi bất kỳ hành vi được xác định.
ugoren

4

Trước tiên, bạn phải hiểu rằng không chỉ x = x ++ mà không được xác định. Không ai quan tâm đến x = x ++, vì dù bạn có định nghĩa gì đi nữa thì cũng không có điểm nào. Những gì không xác định giống như "a = b ++ trong đó a và b xảy ra giống nhau" - tức là

void f(int *a, int *b) {
    *a = (*b)++;
}
int i;
f(&i, &i);

Có một số cách khác nhau mà chức năng có thể được thực hiện, tùy thuộc vào cách hiệu quả nhất cho kiến ​​trúc bộ xử lý (và cho các câu lệnh xung quanh, trong trường hợp đây là một hàm phức tạp hơn so với ví dụ). Ví dụ, hai cái rõ ràng:

load r1 = *b
copy r2 = r1
increment r1
store *b = r1
store *a = r2

hoặc là

load r1 = *b
store *a = r1
increment r1
store *b = r1

Lưu ý rằng cái đầu tiên được liệt kê ở trên, cái đầu tiên sử dụng nhiều hướng dẫn và nhiều thanh ghi hơn, là cái mà bạn sẽ cần phải được sử dụng trong mọi trường hợp a và b không thể được chứng minh là khác nhau.


Bạn thực sự cho thấy một trường hợp mà đề xuất của tôi dẫn đến nhiều hoạt động của máy hơn, nhưng nó có vẻ không đáng kể đối với tôi. Và trình biên dịch vẫn có một số tự do - yêu cầu thực sự duy nhất tôi thêm là lưu trữ btrước đó a.
ugoren

3

Di sản

Giả định rằng C có thể được phát minh lại ngày hôm nay không thể giữ được. Có rất nhiều dòng mã C đã được sản xuất và được sử dụng hàng ngày, việc thay đổi luật chơi ở giữa trò chơi là sai.

Tất nhiên bạn có thể phát minh ra một ngôn ngữ mới, nói C + = , với các quy tắc của bạn. Nhưng đó sẽ không phải là C.


2
Tôi thực sự không nghĩ rằng chúng ta có thể phát minh lại C ngày hôm nay. Điều này không có nghĩa là chúng ta không thể thảo luận về những vấn đề này. Tuy nhiên, những gì tôi đề nghị không thực sự phát minh lại. Chuyển đổi hành vi không xác định thành xác định hoặc không xác định có thể được thực hiện khi cập nhật một tiêu chuẩn và ngôn ngữ vẫn sẽ là C.
ugoren

2

Tuyên bố rằng một cái gì đó được xác định sẽ không thay đổi trình biên dịch hiện có để tôn trọng định nghĩa của bạn. Điều đó đặc biệt đúng trong trường hợp giả định có thể được dựa vào một cách rõ ràng hoặc ngầm ở nhiều nơi.

Vấn đề chính của giả định không phải là x = x++;(trình biên dịch có thể dễ dàng kiểm tra và nên cảnh báo), đó là *p1 = (*p2)++và tương đương ( p1[i] = p2[j]++;khi p1 và p2 là tham số cho hàm) trong đó trình biên dịch không thể biết dễ dàng nếup1 == p2 (trong C99 restrictđã được thêm vào để phổ biến khả năng giả sử p1! = p2 giữa các điểm chuỗi, do đó, các khả năng tối ưu hóa là quan trọng).


Tôi không thấy đề nghị của tôi thay đổi bất cứ điều gì liên quan đến p1[i]=p2[j]++. Nếu trình biên dịch có thể giả sử không có răng cưa thì không có vấn đề gì. Nếu không thể, nó phải đi theo sách - tăng p2[j]trước, lưu trữ p1[i]sau. Ngoại trừ các cơ hội tối ưu hóa bị mất, có vẻ không đáng kể, tôi thấy không có vấn đề gì.
xấu xí

Đoạn thứ hai không độc lập với đoạn đầu tiên, nhưng là một ví dụ về loại địa điểm mà giả định có thể len ​​vào và sẽ khó theo dõi.
Lập trình viên

Đoạn đầu tiên nêu một điều khá rõ ràng - trình biên dịch sẽ phải được thay đổi để tuân thủ một tiêu chuẩn mới. Tôi thực sự không nghĩ rằng tôi có cơ hội để chuẩn hóa điều này và làm cho các nhà văn trình biên dịch tuân theo. Tôi chỉ nghĩ rằng nó đáng để thảo luận.
ugoren

Vấn đề không phải là người ta cần thay đổi trình biên dịch về bất kỳ thay đổi nào trong ngôn ngữ cần nó, đó là những thay đổi có sức lan tỏa và khó tìm thấy. Cách tiếp cận hầu hết thực tế có lẽ sẽ được thay đổi định dạng trung gian mà trên đó các công trình tối ưu, tức là giả vờ rằng x = x++;đã không được viết nhưng t = x; x++; x = t;hay x=x; x++;hay bất cứ điều gì bạn muốn như ngữ nghĩa (nhưng những gì về chẩn đoán?). Đối với một ngôn ngữ mới, chỉ cần bỏ tác dụng phụ.
AProgrammer

Tôi không biết quá nhiều về cấu trúc trình biên dịch. Nếu tôi thực sự muốn thay đổi tất cả các trình biên dịch, tôi sẽ quan tâm nhiều hơn. Nhưng có thể coi x++như là một điểm thứ tự, như thể đó là một lời gọi hàm inc_and_return_old(&x)sẽ thực hiện thủ thuật.
ugoren

-1

Trong một số trường hợp, loại mã này đã được xác định trong Tiêu chuẩn C ++ 11 mới.


5
Quan tâm đến công phu?
xấu xí

Tôi nghĩ x = ++xbây giờ đã được xác định rõ (nhưng không x = x++)
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.