Câu hỏi Các so sánh trên các con trỏ nằm ngoài phạm vi được xác định rõ?


Với mã sau:

char buffer[1024];
char * const begin = buffer;
char * const end = buffer + 1024;
char *p = begin + 2000;
if (p < begin || p > end)
    std::cout << "pointer is out of range\n";

Các so sánh có được thực hiện hay không (p < begin và p > end) được xác định rõ? Hoặc mã này có hành vi không xác định bởi vì con trỏ đã được nâng cao qua cuối mảng?

Nếu so sánh được xác định rõ, định nghĩa đó là gì?

(tín dụng phụ: là đánh giá begin + 2000 bản thân hành vi không xác định?)


13
2017-12-21 21:01


gốc


Tôi nghĩ rằng câu trả lời chỉ là con trỏ một trong quá khứ kết thúc và NULL, nhưng tôi không thể trích dẫn chương và câu. - Flexo♦
Trên một hệ thống có bộ nhớ phân đoạn, địa chỉ begin + 2000 có thể không tồn tại. - Bo Persson
Có hai khái niệm khác nhau trong câu hỏi này: so sánh các con trỏ và tạo ra các giá trị con trỏ. Chúng ta phải quyết định xem begin + 2000 thậm chí được xác định rõ trước khi chúng tôi hỏi về các so sánh con trỏ. Tôi không nghĩ vậy. Tuy nhiên, khi chúng tôi có hai con trỏ hợp lệ, bạn có thể hỏi cách so sánh chúng. Như ghi chú câu trả lời của Mat, nó không được xác định nói chung. Tuy nhiên, bạn có thể sử dụng std::less<> (et. al.) để có được tổng số thứ tự trên các giá trị con trỏ, ngay cả khi sử dụng < trực tiếp không xác định. - GManNickG


Các câu trả lời:


Việc đánh giá begin+2000 là không xác định, nó sẽ đi qua phần cuối của mảng - bạn có thể đi lên đến một trong quá khứ, nhưng không xa hơn.

Từ C ++ 11 §5.7 / 5 Toán tử phụ gia:

Khi một biểu thức có kiểu tách rời được thêm vào hoặc trừ khỏi một con trỏ, kết quả có kiểu toán tử con trỏ. Nếu toán hạng con trỏ trỏ tới phần tử của đối tượng mảng, và mảng đủ lớn, kết quả trỏ đến phần tử offset từ phần tử gốc sao cho sự khác biệt của các phần tử con của các phần tử mảng kết quả và nguyên bản bằng biểu thức tích phân. [...] Nếu cả toán tử con trỏ và điểm kết quả cho các phần tử của cùng một đối tượng mảng hoặc một phần tử cuối cùng của đối tượng mảng, thì việc đánh giá sẽ không tạo ra tràn; nếu không, hành vi là   chưa xác định.

Để so sánh con trỏ được chỉ định, giả sử bạn có con trỏ hợp lệ để bắt đầu, chúng về cơ bản cần trỏ đến cùng một mảng (hoặc một trong quá khứ), hoặc con trỏ tới các thành viên dữ liệu không tĩnh của cùng một điều khiển truy cập giống nhau đối tượng (trừ khi đó là một liên minh ...).

Các chi tiết có trong §5.9 / 2 Các toán tử quan hệ:

Con trỏ đến các đối tượng hoặc chức năng cùng loại (sau khi chuyển đổi con trỏ) có thể được so sánh, với kết quả được xác định như sau:

  • Nếu hai con trỏ p và q của cùng một loại điểm đến cùng một đối tượng hoặc chức năng, hoặc cả hai điểm một trong quá khứ   kết thúc của cùng một mảng, hoặc là cả hai null, sau đó p <= q và p> = q cả hai sản lượng đúng và p <q và p> q   cả hai sản lượng đều sai.
  • Nếu hai con trỏ p và q của cùng một điểm trỏ đến các đối tượng khác nhau không phải là thành viên của cùng một   đối tượng hoặc các phần tử của cùng một mảng hoặc các hàm khác nhau, hoặc nếu chỉ một trong số chúng là null, kết quả   của p <q, p> q, p <= q và p> = q không xác định.
  • Nếu hai con trỏ trỏ đến các thành viên dữ liệu không tĩnh của cùng một đối tượng hoặc cho các phần tử con hoặc phần tử mảng   của các thành viên như vậy, đệ quy, con trỏ đến thành viên được khai báo sau đó so sánh lớn hơn với điều kiện   hai thành viên có cùng quyền kiểm soát truy cập (Điều 11) và cung cấp lớp học của họ không phải là một công đoàn.
  • Nếu hai con trỏ trỏ đến các thành viên dữ liệu không tĩnh của cùng một đối tượng với điều khiển truy cập khác nhau   (Điều 11) kết quả không được chỉ định.   - Nếu hai con trỏ trỏ tới các thành viên dữ liệu không tĩnh của cùng một đối tượng công đoàn, chúng sẽ so sánh bằng nhau (sau   chuyển đổi thành void *, nếu cần). Nếu hai con trỏ trỏ đến các phần tử của cùng một mảng hoặc một phần tử   kết thúc của mảng, con trỏ tới đối tượng có chỉ số cao hơn so sánh cao hơn.
  • Các so sánh con trỏ khác không xác định.

6
2017-12-21 21:10



Về lý do tại sao điều này là, nó có thể hiểu được rằng buffer có thể được cấp phát tại địa chỉ 500 trong bộ nhớ chỉ lớn 2048 byte. Vì thế begin sẽ là 500 và p sẽ là 2500. Nhưng kể từ khi bộ nhớ chỉ có 2048 lớn (và do đó con trỏ chỉ dài 11 bit), những gì bạn thực sự có được cho p là địa chỉ 452 - phía trước của buffer. (Có, ví dụ này là giả tạo, nhưng có rất nhiều thực tế các sơ đồ bộ nhớ phân đoạn không cái đó khác nhau.) - Hot Licks
Lưu ý rằng bạn có thể sử dụng std::less<> (et. al.) để có được tổng số thứ tự trên các con trỏ không liên quan (mặc dù chúng phải, tất nhiên, vẫn còn có giá trị hợp lệ, đó là một điều hoàn toàn khác nhau alotgether). - GManNickG
Nhưng tất nhiên "đặt hàng" của con trỏ không liên quan phần lớn là vô nghĩa. - Hot Licks
-1: p không phải là một con trỏ tới một đối tượng. - Potatoswatter
@Mat Nó không trỏ đến bất cứ điều gì. Không có cái gì ở đó;" nó không hợp lệ. Tôi đặt "ở đó" trong dấu ngoặc kép vì giá trị con trỏ không thể được tính toán một cách hợp pháp ngay từ đầu. Thậm chí không có một địa điểm nào ở đó. Xem các câu trả lời khác. - Potatoswatter


Tôi sẽ giả định C ++ 11 Tiêu chuẩn. Theo phần 5.7 (Phụ gia bổ sung) đoạn 5, hành vi của *p = begin + 2000 là không xác định trước, trước khi bạn thậm chí có thể so sánh:

Nếu cả toán tử con trỏ và điểm kết quả cho các phần tử của   cùng một đối tượng mảng, hoặc một phần tử cuối cùng của đối tượng mảng,   việc đánh giá sẽ không tạo ra quá mức; nếu không, hành vi   không được xác định.


10
2017-12-21 22:39





Hành vi của chương trình của bạn không xác định, nhưng không phải do so sánh.

Việc đánh giá biểu thức begin + 2000 có hành vi không xác định bởi vì kết quả sẽ trỏ nhiều hơn một phần tử qua cuối của mảng yếu tố 1024.

Trích dẫn C ++ 11 (thực sự là N3485 bản nháp), 5.7p4 [expr.add]:

Khi biểu thức có loại tích phân được thêm vào hoặc bị trừ   từ một con trỏ, kết quả có kiểu toán tử con trỏ. [...]   Nếu cả toán tử con trỏ và điểm kết quả cho các phần tử của   cùng một đối tượng mảng, hoặc một phần tử cuối cùng của đối tượng mảng,   việc đánh giá sẽ không tạo ra tràn; nếu không, hành vi   không định nghĩa được.

Trong ngắn hạn, chỉ cần tính toán một con trỏ out-of-bounds có hành vi không xác định; nó không quan trọng những hoạt động bạn thực hiện trên con trỏ đó sau đó.


3