Hành vi không xác định, không xác định và thực hiện được xác định


530

Hành vi không xác định trong C và C ++ là gì? Điều gì về hành vi không xác định và hành vi xác định thực hiện? sự khác biệt giữa chúng là gì?


1
Tôi khá chắc chắn rằng chúng tôi đã làm điều này, nhưng tôi không thể tìm thấy nó. Xem thêm: stackoverflow.com/questions/2301372/ Lời
dmckee --- ex-moderator mèo con



1
Đây là một cuộc thảo luận thú vị (phần "Phụ lục L và Hành vi không xác định").
Owen

Câu trả lời:


406

Hành vi không xác định là một trong những khía cạnh của ngôn ngữ C và C ++ có thể gây ngạc nhiên cho các lập trình viên đến từ các ngôn ngữ khác (các ngôn ngữ khác cố gắng che giấu nó tốt hơn). Về cơ bản, có thể viết các chương trình C ++ không hoạt động theo cách có thể dự đoán được, mặc dù nhiều trình biên dịch C ++ sẽ không báo cáo bất kỳ lỗi nào trong chương trình!

Hãy xem xét một ví dụ cổ điển:

#include <iostream>

int main()
{
    char* p = "hello!\n";   // yes I know, deprecated conversion
    p[0] = 'y';
    p[5] = 'w';
    std::cout << p;
}

Biến pchỉ vào chuỗi ký tự "hello!\n"và hai phép gán bên dưới cố gắng sửa đổi chuỗi ký tự đó. Chương trình này làm gì? Theo mục 2.14.5 đoạn 11 của tiêu chuẩn C ++, nó gọi hành vi không xác định :

Hiệu quả của việc cố gắng sửa đổi một chuỗi ký tự là không xác định.

Tôi có thể nghe thấy mọi người hét lên "Nhưng chờ đã, tôi có thể biên dịch điều này không có vấn đề gì và nhận được đầu ra yellow" hoặc "Ý bạn là gì không xác định, chuỗi ký tự được lưu trữ trong bộ nhớ chỉ đọc, vì vậy lần thử đầu tiên sẽ dẫn đến kết xuất lõi". Đây chính xác là vấn đề với hành vi không xác định. Về cơ bản, tiêu chuẩn cho phép bất cứ điều gì xảy ra một khi bạn gọi hành vi không xác định (thậm chí là quỷ mũi). Nếu có một hành vi "đúng" theo mô hình ngôn ngữ tinh thần của bạn, thì mô hình đó đơn giản là sai; Các tiêu chuẩn C ++ có phiếu bầu duy nhất, thời gian.

Các ví dụ khác về hành vi không xác định bao gồm truy cập vào một mảng nằm ngoài giới hạn của nó, hủy bỏ con trỏ null , truy cập các đối tượng sau khi thời gian kết thúc của chúng hoặc viết các biểu thức được cho là thông minh như thế nào i++ + ++i.

Phần 1.9 của tiêu chuẩn C ++ cũng đề cập đến hai anh em ít nguy hiểm hơn, hành vi không xác địnhhành vi được xác định thực hiện :

Các mô tả ngữ nghĩa trong Tiêu chuẩn quốc tế này xác định một máy trừu tượng không tham số hóa.

Một số khía cạnh và hoạt động của máy trừu tượng được mô tả trong Tiêu chuẩn quốc tế này dưới dạng xác định thực hiện (ví dụ sizeof(int):). Chúng tạo thành các tham số của máy trừu tượng. Mỗi thực hiện sẽ bao gồm các tài liệu mô tả các đặc điểm và hành vi của nó trong các khía cạnh này.

Một số khía cạnh và hoạt động khác của máy trừu tượng được mô tả trong Tiêu chuẩn quốc tế này là không xác định (ví dụ: thứ tự đánh giá các đối số cho một hàm). Khi có thể, Tiêu chuẩn quốc tế này xác định một tập hợp các hành vi được phép. Chúng xác định các khía cạnh không xác định của máy trừu tượng.

Một số hoạt động khác được mô tả trong Tiêu chuẩn quốc tế này là không xác định (ví dụ: hiệu ứng của việc hủy bỏ con trỏ null). [ Lưu ý : Tiêu chuẩn quốc tế này áp đặt không có yêu cầu đối với hành vi của các chương trình có chứa hành vi không xác định. - lưu ý cuối ]

Cụ thể, mục 1.3.24 nêu:

Hành vi không xác định cho phép bao gồm từ bỏ qua hoàn toàn tình huống với kết quả không thể đoán trước , đến hành vi trong quá trình dịch thuật hoặc thực hiện chương trình theo đặc tính tài liệu 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 ban hành của một thông điệp chẩn đoán).

Bạn có thể làm gì để tránh chạy vào hành vi không xác định? Về cơ bản, bạn phải đọc những cuốn sách C ++ hay của những tác giả biết họ đang nói về cái gì. Vít hướng dẫn internet. Vít bullschildt.


6
Có một sự thật kỳ lạ xuất phát từ việc hợp nhất rằng câu trả lời này chỉ bao gồm C ++ nhưng các thẻ câu hỏi này bao gồm C. C có một khái niệm khác về "hành vi không xác định": Nó vẫn sẽ yêu cầu triển khai để đưa ra thông báo chẩn đoán ngay cả khi hành vi cũng được nêu không được xác định cho các vi phạm quy tắc nhất định (vi phạm ràng buộc).
Julian Schaub - litb

8
@Benoit Đó là hành vi không xác định vì tiêu chuẩn cho biết đó là hành vi không xác định, thời gian. Trên một số hệ thống, thực sự chuỗi ký tự được lưu trữ trong đoạn văn bản chỉ đọc và chương trình sẽ bị sập nếu bạn cố gắng sửa đổi một chuỗi ký tự. Trên các hệ thống khác, chuỗi ký tự thực sự sẽ xuất hiện thay đổi. Các tiêu chuẩn không bắt buộc những gì phải xảy ra. Đó là những gì hành vi không xác định có nghĩa là.
dòng chảy

5
@FredOverflow, Tại sao một trình biên dịch tốt cho phép chúng tôi biên dịch mã mang lại hành vi không xác định? Chính xác những gì tốt có thể biên dịch loại mã này cung cấp? Tại sao tất cả các trình biên dịch tốt không cung cấp cho chúng ta một dấu hiệu cảnh báo màu đỏ lớn khi chúng ta đang cố gắng biên dịch mã mang lại hành vi không xác định?
Pacerier

14
@Pacerier Có một số thứ không thể kiểm tra được tại thời điểm biên dịch. Ví dụ, không phải lúc nào cũng có thể đảm bảo rằng một con trỏ null không bao giờ bị hủy đăng ký, nhưng điều này không được xác định.
Tim Seguine

4
@Celeritas, hành vi không xác định thể không xác định. Ví dụ, không thể biết trước nội dung của bộ nhớ chưa được khởi tạo sẽ là gì, vd. int f(){int a; return a;}: giá trị của acó thể thay đổi giữa các lệnh gọi hàm.
Đánh dấu

97

Vâng, về cơ bản, đây là một bản sao dán thẳng từ tiêu chuẩn

3.4.1 1 hành vi được xác định theo thực hiện Hành vi không xác định trong đó mỗi tài liệu thực hiện cách lựa chọn được thực hiện

2 VÍ DỤ Một ví dụ về hành vi được xác định thực hiện là sự lan truyền của bit thứ tự cao khi một số nguyên được ký được dịch chuyển sang phải.

3.4.3 1 hành vi hành vi không xác định , khi sử dụng cấu trúc chương trình không thể truy cập hoặc có lỗi hoặc dữ liệu sai, mà Tiêu chuẩn quốc tế này áp đặt không có yêu cầu

2 LƯU Ý Hành vi không xác định có thể bao gồm từ bỏ qua hoàn toàn tình huống với kết quả không thể đoán trước, đến hành vi trong quá trình dịch hoặc thực hiện chương trình theo đặc tính của tài liệu về môi trường (có hoặc không có thông báo chẩn đoán), để chấm dứt dịch hoặc thực hiện (với việc phát hành một thông điệp chẩn đoán).

3 VÍ DỤ Một ví dụ về hành vi không xác định là hành vi trên tràn số nguyên.

3.4.4 1 hành vi không xác định sử dụng một giá trị không xác định hoặc hành vi khác trong đó Tiêu chuẩn quốc tế này cung cấp hai hoặc nhiều khả năng và không áp dụng thêm các yêu cầu nào được chọn trong bất kỳ trường hợp nào

2 VÍ DỤ Một ví dụ về hành vi không xác định là thứ tự mà các đối số cho hàm được ước tính.


3
Sự khác biệt giữa hành vi được xác định thực hiện và không xác định là gì?
Zolomon

26
@Zolomon: Giống như nó nói: về cơ bản là điều tương tự, ngoại trừ trong trường hợp triển khai được xác định, việc triển khai được yêu cầu để ghi lại (để đảm bảo) những gì chính xác sẽ xảy ra, trong trường hợp không xác định thì việc thực hiện không bắt buộc phải ghi lại hoặc đảm bảo bất cứ điều gì.
AnT

1
@Zolomon: Nó được phản ánh trong sự khác biệt giữa 3.4.1 và 2.4.4.
sbi

8
@Celeritas: Trình biên dịch siêu hiện đại có thể làm tốt hơn thế. Đưa ra int foo(int x) { if (x >= 0) launch_missiles(); return x << 1; }một trình biên dịch có thể xác định rằng vì tất cả các phương tiện gọi hàm không khởi động tên lửa đều gọi Hành vi không xác định, nên nó có thể thực hiện cuộc gọi đến launch_missiles()vô điều kiện.
supercat

2
@northerner Như trích dẫn nêu, hành vi không xác định thường bị giới hạn trong một tập hợp hạn chế các hành vi có thể. Trong một số trường hợp, bạn thậm chí có thể đưa ra kết luận rằng tất cả các khả năng này đều được chấp nhận trong bối cảnh cụ thể, trong trường hợp đó, hành vi không xác định hoàn toàn không phải là vấn đề. Hành vi không xác định là hoàn toàn không bị hạn chế (eb "chương trình có thể quyết định định dạng ổ cứng của bạn"). Hành vi không xác định luôn luôn là một vấn đề.
AnT

60

Có lẽ từ ngữ dễ hiểu có thể dễ hiểu hơn định nghĩa khắt khe của các tiêu chuẩn.

hành vi xác định thực hiện
Ngôn ngữ nói rằng chúng ta có kiểu dữ liệu. Các nhà cung cấp trình biên dịch xác định kích thước họ sẽ sử dụng và cung cấp tài liệu về những gì họ đã làm.

hành vi không xác định
Bạn đang làm gì đó sai. Ví dụ: bạn có một giá trị rất lớn intkhông phù hợp char. Làm thế nào để bạn đặt giá trị đó trong char? Thật ra không có cách nào! Bất cứ điều gì cũng có thể xảy ra, nhưng điều hợp lý nhất sẽ là lấy byte đầu tiên của int đó và đặt nó vào char. Thật sai lầm khi chỉ định byte đầu tiên, nhưng đó là những gì xảy ra dưới mui xe.

hành vi không xác định
Chức năng nào của hai điều này được thực hiện trước?

void fun(int n, int m);

int fun1()
{
  cout << "fun1";
  return 1;
}
int fun2()
{
  cout << "fun2";
  return 2;
}
...
fun(fun1(), fun2()); // which one is executed first?

Ngôn ngữ không chỉ định đánh giá, từ trái sang phải hoặc phải sang trái! Vì vậy, một hành vi không xác định có thể hoặc không thể dẫn đến một hành vi không xác định, nhưng chắc chắn chương trình của bạn không được tạo ra một hành vi không xác định.


@eSKay Tôi nghĩ rằng câu hỏi của bạn đáng để chỉnh sửa câu trả lời để làm rõ hơn :)

cho fun(fun1(), fun2());không phải là hành vi "thực hiện được xác định"? Trình biên dịch phải chọn một hoặc khóa học khác, sau tất cả?

Sự khác biệt giữa định nghĩa triển khai và không xác định, là trình biên dịch có nghĩa vụ chọn một hành vi trong trường hợp đầu tiên nhưng nó không phải trong trường hợp thứ hai. Ví dụ, một triển khai phải có một và chỉ một định nghĩa về sizeof(int). Vì vậy, không thể nói đó sizeof(int)là 4 cho một số phần của chương trình và 8 cho các phần khác. Không giống như hành vi không xác định, nơi trình biên dịch có thể nói OK Tôi sẽ đánh giá các đối số này từ trái sang phải và các đối số của hàm tiếp theo được đánh giá từ phải sang trái. Nó có thể xảy ra trong cùng một chương trình, đó là lý do tại sao nó được gọi là không xác định . Trên thực tế, C ++ có thể đã được thực hiện dễ dàng hơn nếu một số hành vi không xác định được chỉ định. Hãy xem câu trả lời của Tiến sĩ Stroustrup cho điều đó :

Người ta khẳng định rằng sự khác biệt giữa những gì có thể được tạo ra mang lại cho trình biên dịch sự tự do này và yêu cầu "đánh giá từ trái sang phải" thông thường có thể là đáng kể. Tôi không tin, nhưng với vô số trình biên dịch "ngoài kia" lợi dụng tự do và một số người nhiệt tình bảo vệ tự do đó, một sự thay đổi sẽ khó khăn và có thể mất hàng thập kỷ để thâm nhập vào các góc xa của thế giới C và C ++. Tôi thất vọng vì không phải tất cả các trình biên dịch đều cảnh báo chống lại mã như ++ i + i ++. Tương tự, thứ tự đánh giá các đối số là không xác định.

IMO quá nhiều "điều" không được xác định, không xác định, xác định thực hiện, v.v. Tuy nhiên, điều đó dễ nói và thậm chí để đưa ra ví dụ về, nhưng khó sửa. Cũng cần lưu ý rằng không khó để tránh hầu hết các vấn đề và tạo mã di động.


1
cho fun(fun1(), fun2());không phải là hành vi "implementation defined"? Trình biên dịch phải chọn một hoặc khóa học khác, sau tất cả?
Lazer

1
@AraK: cảm ơn đã giải thích. Tôi hiểu nó bây giờ. Btw, "I am gonna evaluate these arguments left-to-right and the next function's arguments are evaluated right-to-left"tôi hiểu điều này canxảy ra. Có thực sự, với trình biên dịch mà chúng ta sử dụng ngày nay?
Lazer

1
@eSKay Bạn phải hỏi một bậc thầy về điều này, người đã nhúng tay vào nhiều trình biên dịch :) AFAIK VC đánh giá các đối số từ phải sang trái luôn.
AraK

4
@Lazer: Nó chắc chắn có thể xảy ra. Kịch bản đơn giản: foo (bar, boz ()) và foo (boz (), bar), trong đó thanh là một int và boz () là một hàm trả về int. Giả sử một CPU trong đó các tham số dự kiến ​​sẽ được truyền vào các thanh ghi R0-R1. Kết quả chức năng được trả về trong R0; chức năng có thể rác R1. Đánh giá "thanh" trước "boz ()" sẽ yêu cầu lưu một bản sao của thanh ở một nơi khác trước khi gọi boz () và sau đó tải bản sao đã lưu đó. Đánh giá "thanh" sau "boz ()" sẽ tránh việc lưu trữ bộ nhớ và tìm nạp lại và là một tối ưu hóa mà nhiều trình biên dịch sẽ thực hiện bất kể thứ tự của chúng trong danh sách đối số.
supercat

6
Tôi không biết về C ++ nhưng tiêu chuẩn C nói rằng việc chuyển đổi int thành char là xác định hoặc thậm chí được xác định rõ (tùy thuộc vào giá trị thực tế và độ ký của các loại). Xem C99 §6.3.1.3 (không thay đổi trong C11).
Nikolai Ruhe

27

Từ tài liệu hợp lý C chính thức

Các thuật ngữ hành vi không xác định , hành vi không xác định và hành vi được xác định thực hiện được sử dụng để phân loại kết quả của việc viết chương trình có các thuộc tính mà Tiêu chuẩn không hoặc không thể mô tả hoàn toàn. Mục tiêu của việc áp dụng phân loại này là cho phép một số loại nhất định trong số các triển khai cho phép chất lượng thực hiện trở thành một lực lượng tích cực trên thị trường cũng như cho phép các tiện ích mở rộng phổ biến nhất định, mà không loại bỏ bộ đệm tuân thủ Tiêu chuẩn. Phụ lục F của Danh mục tiêu chuẩn những hành vi thuộc một trong ba loại này.

Hành vi không xác định cung cấp cho người thực hiện một số vĩ độ trong việc dịch các chương trình. Vĩ độ này không kéo dài đến mức không thể dịch chương trình.

Hành vi không xác định cung cấp cho giấy phép người thực hiện không bắt lỗi nhất định của chương trình khó chẩn đoán. Nó cũng xác định các khu vực có thể mở rộng ngôn ngữ phù hợp: người triển khai có thể tăng ngôn ngữ bằng cách cung cấp định nghĩa về hành vi không xác định chính thức.

Hành vi được xác định theo thực hiện cho phép người thực hiện tự do lựa chọn cách tiếp cận phù hợp, nhưng yêu cầu lựa chọn này phải được giải thích cho người dùng. Các hành vi được chỉ định là định nghĩa triển khai thường là những hành vi mà người dùng có thể đưa ra quyết định mã hóa có ý nghĩa dựa trên định nghĩa triển khai. Các nhà triển khai nên ghi nhớ tiêu chí này khi quyết định mức độ mở rộng của một định nghĩa triển khai. Như với hành vi không xác định, chỉ đơn giản là không dịch nguồn có chứa hành vi được xác định thực hiện không phải là một phản hồi thích hợp.


3
Các nhà văn trình biên dịch siêu hiện đại cũng coi "hành vi không xác định" là cấp giấy phép cho người viết trình biên dịch để cho rằng các chương trình sẽ không bao giờ nhận được các đầu vào gây ra Hành vi không xác định và thay đổi tùy ý tất cả các khía cạnh về cách các chương trình hoạt động khi họ nhận các đầu vào đó.
supercat

2
Một điểm khác tôi chỉ nhận thấy: C89 không sử dụng thuật ngữ "tiện ích mở rộng" để mô tả các tính năng được đảm bảo trên một số triển khai nhưng không phải là các tính năng khác. Các tác giả của C89 đã nhận ra rằng phần lớn các triển khai hiện tại sau đó sẽ xử lý số học đã ký và số học không dấu, ngoại trừ khi kết quả được sử dụng theo một số cách nhất định và điều trị như vậy được áp dụng ngay cả trong trường hợp tràn ký; tuy nhiên, họ không liệt kê đó là một phần mở rộng phổ biến trong Phụ lục J2, tuy nhiên, điều đó cho tôi thấy họ đã xem nó như một trạng thái tự nhiên, thay vì một phần mở rộng.
supercat

10

Hành vi không xác định so với Hành vi không xác định có một mô tả ngắn về nó.

Tóm tắt cuối cùng của họ:

Tóm lại, hành vi không xác định thường là điều bạn không nên lo lắng, trừ khi phần mềm của bạn bắt buộc phải có thể mang theo được. Ngược lại, hành vi không xác định luôn luôn là không mong muốn và không bao giờ nên xảy ra.


1
Có hai loại trình biên dịch: những trình biên dịch, trừ khi được ghi lại rõ ràng bằng cách khác, diễn giải hầu hết các dạng Hành vi không xác định của Tiêu chuẩn là quay trở lại với các hành vi đặc trưng được ghi lại bởi môi trường bên dưới và những hành vi mặc định chỉ phơi bày một cách hữu ích các hành vi mà Tiêu chuẩn mô tả là Thực hiện-Xác định. Khi sử dụng trình biên dịch loại đầu tiên, nhiều thứ thuộc loại đầu tiên có thể được thực hiện một cách hiệu quả và an toàn bằng cách sử dụng UB. Trình biên dịch cho loại thứ hai sẽ chỉ phù hợp cho các tác vụ đó nếu chúng cung cấp các tùy chọn để đảm bảo hành vi trong các trường hợp đó.
supercat

8

Về mặt lịch sử, cả hai Hành vi được xác định theo thực hiện và Hành vi không xác định đều thể hiện các tình huống trong đó các tác giả của Tiêu chuẩn dự kiến ​​rằng mọi người viết các triển khai chất lượng sẽ sử dụng phán đoán để quyết định những gì đảm bảo hành vi, nếu có, sẽ hữu ích cho các chương trình trong trường ứng dụng dự định chạy trên mục tiêu dự định. Nhu cầu của mã crunching số cao cấp khá khác biệt so với mã hệ thống cấp thấp, và cả UB và IDB đều cho phép người viết trình biên dịch linh hoạt để đáp ứng các nhu cầu khác nhau đó. Không thể loại nào bắt buộc các triển khai thực hiện theo cách hữu ích cho bất kỳ mục đích cụ thể nào, hoặc thậm chí cho bất kỳ mục đích nào. Tuy nhiên, việc triển khai chất lượng được cho là phù hợp cho một mục đích cụ thể, tuy nhiên, nên hành xử theo cách phù hợp với mục đích đódù Tiêu chuẩn có yêu cầu hay không .

Sự khác biệt duy nhất giữa Hành vi được Xác định Thực hiện và Hành vi Không xác định là trước đây yêu cầu việc triển khai xác định và ghi lại hành vi nhất quán ngay cả trong trường hợp việc triển khai không thể làm gì có thể hữu ích . Đường phân chia giữa chúng không phải là liệu có hữu ích cho việc triển khai để xác định hành vi hay không (người viết trình biên dịch nên xác định hành vi hữu ích khi thực tế cho dù Tiêu chuẩn có yêu cầu chúng hay không) mà là có thể thực hiện đồng thời việc xác định hành vi có tốn kém không và vô dụng . Một phán quyết rằng việc triển khai như vậy có thể tồn tại không theo bất kỳ cách nào, hình dạng hoặc hình thức, ngụ ý bất kỳ phán xét nào về tính hữu ích của việc hỗ trợ một hành vi được xác định trên các nền tảng khác.

Thật không may, kể từ giữa những năm 1990, các nhà văn biên dịch đã bắt đầu hiểu việc thiếu các nhiệm vụ hành vi là một phán quyết rằng đảm bảo hành vi không đáng giá ngay cả trong các lĩnh vực ứng dụng, nơi chúng rất quan trọng và thậm chí trên các hệ thống mà thực tế chúng không tốn kém. Thay vì điều trị UB như một lời mời để thực hiện phán quyết hợp lý, nhà văn biên dịch đã bắt đầu xử lý nó như một cái cớ không làm như vậy.

Ví dụ, đưa ra mã sau đây:

int scaled_velocity(int v, unsigned char pow)
{
  if (v > 250)
    v = 250;
  if (v < -250)
    v = -250;
  return v << pow;
}

việc thực hiện bổ sung hai sẽ không phải tốn bất kỳ nỗ lực nào để coi biểu thức v << powlà sự thay đổi bổ sung của hai mà không quan tâm đến việc vtích cực hay tiêu cực.

Tuy nhiên, triết lý ưa thích của một số người viết trình biên dịch ngày nay sẽ đề xuất rằng vì vchỉ có thể âm nếu chương trình sẽ tham gia vào Hành vi không xác định, không có lý do gì để chương trình đưa ra phạm vi phủ định v. Mặc dù dịch chuyển trái của các giá trị âm được sử dụng để hỗ trợ cho mỗi trình biên dịch có ý nghĩa duy nhất và một lượng lớn mã hiện có phụ thuộc vào hành vi đó, triết học hiện đại sẽ giải thích thực tế rằng Tiêu chuẩn nói rằng các giá trị âm thay đổi trái là UB ngụ ý rằng các nhà văn trình biên dịch nên thoải mái bỏ qua điều đó.


Nhưng xử lý hành vi không xác định theo cách tốt đẹp không miễn phí. Toàn bộ lý do mà các trình biên dịch hiện đại thể hiện hành vi kỳ quái như vậy trong một số trường hợp của UB là chúng không ngừng tối ưu hóa, và để làm tốt nhất công việc đó, chúng phải có thể cho rằng UB không bao giờ xảy ra.
Tom Swirly

Nhưng thực tế <<là UB trên các số âm là một cái bẫy nhỏ khó chịu và tôi rất vui khi được nhắc về điều đó!
Tom Swirly

1
@TomSwirly: Thật không may, người viết trình biên dịch không quan tâm đến việc cung cấp các đảm bảo hành vi lỏng lẻo ngoài các quy định bắt buộc bởi Tiêu chuẩn thường có thể cho phép tăng tốc độ lớn so với yêu cầu tránh mã đó bằng mọi giá không được xác định bởi Tiêu chuẩn. Nếu một lập trình viên không quan tâm đến việc i+j>kmang lại 1 hay 0 trong trường hợp bổ sung tràn ra, miễn là nó không có tác dụng phụ nào khác , trình biên dịch có thể thực hiện một số tối ưu hóa lớn không thể thực hiện được nếu lập trình viên viết mã như (int)((unsigned)i+j) > k.
supercat

1
@TomSwirly: Đối với họ, nếu trình biên dịch X có thể thực hiện chương trình tuân thủ nghiêm ngặt để thực hiện một số tác vụ T và mang lại hiệu năng thực thi hiệu quả hơn 5% so với trình biên dịch Y sẽ mang lại cùng chương trình đó, điều đó có nghĩa là X tốt hơn, ngay cả khi Y có thể tạo mã đã thực hiện cùng một tác vụ ba lần một cách hiệu quả khi đưa ra một chương trình khai thác các hành vi mà Y đảm bảo nhưng X thì không.
supercat

6

Tiêu chuẩn C ++ n3337 § 1.3.10 hành vi được xác định thực hiện

hành vi, đối với một chương trình được xây dựng tốt và dữ liệu chính xác, điều đó phụ thuộc vào việc thực hiện và mỗi tài liệu thực hiện

Đôi khi, C ++ Standard không áp đặt hành vi cụ thể cho một số cấu trúc mà thay vào đó nói rằng một hành vi cụ thể, được xác định rõ ràng phải được chọn và mô tả bằng cách triển khai cụ thể (phiên bản của thư viện). Vì vậy, người dùng vẫn có thể biết chính xác chương trình sẽ hoạt động như thế nào mặc dù Standard không mô tả điều này.


Tiêu chuẩn C ++ n3337 § 1.3.24 hành vi không xác định

hành vi mà Tiêu chuẩn quốc tế này áp đặt không có yêu cầu [Lưu ý: Hành vi không xác định có thể được mong đợi khi Tiêu chuẩn quốc tế này bỏ qua bất kỳ định nghĩa rõ ràng nào về hành vi hoặc khi chương trình sử dụng cấu trúc sai hoặc dữ liệu sai. Hành vi không xác định cho phép bao gồm từ bỏ qua hoàn toàn tình huống với kết quả không thể đoán trước, đến hành vi trong quá trình dịch thuật hoặc thực hiện chương trình theo đặc tính tài liệu 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 ban hành của một thông điệp chẩn đoán). Nhiều cấu trúc chương trình sai lầm không gây ra hành vi không xác định; họ được yêu cầu phải được chẩn đoán. - lưu ý cuối]

Khi chương trình gặp phải cấu trúc không được xác định theo Tiêu chuẩn C ++, nó được phép làm bất cứ điều gì nó muốn làm (có thể gửi email cho tôi hoặc có thể gửi email cho bạn hoặc có thể bỏ qua mã hoàn toàn).


Tiêu chuẩn C ++ n3337 § 1.3.25 hành vi không xác định

hành vi, đối với một chương trình được xây dựng tốt và dữ liệu chính xác, điều đó phụ thuộc vào việc thực hiện [Lưu ý: Việc thực hiện là không bắt buộc để ghi lại hành vi nào xảy ra. Phạm vi của các hành vi có thể thường được phân định theo Tiêu chuẩn quốc tế này. - lưu ý cuối]

C ++ Standard không áp đặt hành vi cụ thể cho một số cấu trúc mà thay vào đó nói rằng một hành vi cụ thể, được xác định rõ ràng phải được chọn ( bot không cần mô tả ) bằng cách triển khai cụ thể (phiên bản của thư viện). Vì vậy, trong trường hợp khi không có mô tả nào được cung cấp, người dùng có thể khó biết chính xác chương trình sẽ ứng xử như thế nào.


6

Xác định thực hiện-

Người triển khai muốn, nên được ghi chép tốt, tiêu chuẩn đưa ra lựa chọn nhưng chắc chắn sẽ biên dịch

Không xác định -

Tương tự như định nghĩa thực hiện nhưng không được ghi lại

Chưa xác định-

Bất cứ điều gì có thể xảy ra, hãy chăm sóc nó.


2
Tôi nghĩ điều quan trọng cần lưu ý là ý nghĩa thực tế của "không xác định" đã thay đổi trong vài năm qua. Nó được sử dụng để đưa ra uint32_t s;, đánh giá 1u<<skhi s33 tuổi có thể được dự kiến ​​có thể mang lại 0 hoặc có thể mang lại 2, nhưng không làm bất cứ điều gì khác lập dị. Tuy nhiên, các trình biên dịch mới hơn, việc đánh giá 1u<<scó thể khiến trình biên dịch xác định rằng vì strước đó phải có ít hơn 32, bất kỳ mã nào trước hoặc sau biểu thức đó chỉ có liên quan nếu scó từ 32 trở lên có thể bị bỏ qua.
supercat
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.