Tôi đang ở giữa cuộc thảo luận đang cố gắng tìm hiểu xem truy cập không được gán có cho phép trong C++ thông qua reinterpret_cast
hay không. Tôi nghĩ là không, nhưng tôi đang gặp khó khăn trong việc tìm đúng (các) phần của tiêu chuẩn xác nhận hoặc bác bỏ điều đó. Tôi đã xem xét C++ 11, nhưng tôi sẽ ổn với phiên bản khác nếu nó rõ ràng hơn.Truy cập chưa được chỉ định thông qua reinterpret_cast
Truy cập chưa được chỉ định không được xác định trong C11. Phần có liên quan của the C11 standard (§ 6.3.2.3, đoạn 7):
Một con trỏ tới loại đối tượng có thể được chuyển thành con trỏ thành loại đối tượng khác. Nếu con trỏ kết quả không được căn chỉnh chính xác cho loại được tham chiếu, hành vi sẽ không được xác định.
Do hành vi của truy cập chưa được ký là không xác định, một số trình biên dịch (ít nhất GCC) thực hiện điều đó có nghĩa là bạn có thể tạo hướng dẫn yêu cầu dữ liệu liên kết. Hầu hết thời gian mã vẫn hoạt động cho dữ liệu chưa được ký vì hầu hết các lệnh x86 và ARM trong những ngày này làm việc với dữ liệu chưa được ký, nhưng một số thì không. Đặc biệt, một số hướng dẫn vector không, có nghĩa là khi trình biên dịch nhận được tốt hơn khi tạo mã hướng dẫn tối ưu mà làm việc với các phiên bản cũ hơn của trình biên dịch có thể không hoạt động với các phiên bản mới hơn. Và, tất nhiên, một số kiến trúc (like MIPS) không hoạt động tốt với dữ liệu chưa được ký.
C++11 là, tất nhiên, phức tạp hơn. § 5.2.10, đoạn 7 cho biết:
Một con trỏ đối tượng có thể được chuyển đổi thành con trỏ đối tượng thuộc loại khác. Khi giá trị “
v
”, được chuyển thành loại “con trỏ thành cvT2
”, kết quả làstatic_cast<cv T2*>(static_cast<cv void*>(v))
nếu cả haiT1
vàT2
là loại bố cục tiêu chuẩn (3.9) và yêu cầu căn chỉnhT2
không chặt chẽ hơn củaT1
hoặc nếu một trong hai loại làvoid
. Chuyển đổi giá trị của loại “con trỏ thànhT1
” thành loại “con trỏ thànhT2
” (trong đóT1
vàT2
là loại đối tượng và yêu cầu căn chỉnhT2
không chặt chẽ hơn so với sốT1
) và quay lại loại ban đầu. giá trị con trỏ. Kết quả của bất kỳ chuyển đổi con trỏ nào khác không được chỉ định.
Lưu ý rằng từ cuối cùng là "không xác định", không phải "không xác định". § 1.3.25 định nghĩa "hành vi không xác định" như:
hành vi, cho một cấu trúc chương trình cũng như hình thành và dữ liệu chính xác, mà phụ thuộc vào việc thực hiện
[Note: Việc thực hiện không cần phải tài liệu mà hành vi xảy ra. Phạm vi của các hành vi có thể thường được mô tả theo tiêu chuẩn này. - cuối note]
Trừ khi tôi là thiếu cái gì, tiêu chuẩn không thực sự phân định phạm vi của các hành vi có thể trong trường hợp này, mà dường như để chỉ cho tôi rằng một hành vi rất hợp lý là đó là thực hiện cho C (ít nhất là bởi GCC): không hỗ trợ họ. Điều đó có nghĩa là trình biên dịch là miễn phí để giả định truy cập unaligned không xảy ra và phát ra các hướng dẫn mà có thể không làm việc với bộ nhớ unaligned, giống như nó không cho C.
Người tôi đang thảo luận điều này, tuy nhiên, có cách giải thích khác. Họ trích dẫn § 1.9, đoạn 5:
Thực hiện tuân thủ thực hiện một chương trình được định dạng tốt sẽ tạo ra hành vi quan sát tương tự như một trong những thực thi có thể của trường hợp tương ứng của máy trừu tượng với cùng chương trình và giống nhau đầu vào. Tuy nhiên, nếu bất kỳ việc thực thi nào như vậy có chứa một hoạt động không xác định, tiêu chuẩn này không yêu cầu thực thi chương trình đó với đầu vào đó (thậm chí không liên quan đến các hoạt động trước hoạt động không xác định đầu tiên).
Vì không có hành vi undefined, họ cho rằng trình biên dịch C++ không có quyền giả định quyền truy cập chưa được căn chỉnh sẽ không xảy ra.
Vì vậy, các truy cập chưa được ký thông qua reinterpret_cast
có an toàn trong C++ không? Ở đâu trong các đặc điểm kỹ thuật (bất kỳ phiên bản) nào nó nói?
Chỉnh sửa: Bằng cách "truy cập", ý tôi là thực sự đang tải và lưu trữ. Một cái gì đó như
void unaligned_cp(void* a, void* b) {
*reinterpret_cast<volatile uint32_t*>(a) =
*reinterpret_cast<volatile uint32_t*>(b);
}
Làm thế nào bộ nhớ được phân bổ là thực sự bên ngoài phạm vi của tôi (đó là một thư viện mà có thể được gọi với dữ liệu từ bất cứ nơi nào), nhưng malloc
và một mảng trên stack đều ứng cử viên có khả năng. Tôi không muốn đặt bất kỳ hạn chế nào về cách phân bổ bộ nhớ.
Chỉnh sửa 2: Hãy trích dẫn nguồn (ví dụ: , chuẩn C++, phần và đoạn) trong câu trả lời.
Truy cập có nghĩa là gì? Aliasing, hoặc chỉ cần đúc các loại con trỏ đến và fro? – Columbo
Bí danh — đặc biệt, tôi quan tâm đến tải và cửa hàng để sắp xếp sai 'uint32_t's. – nemequ
Nó có thể giúp thảo luận nếu bạn đăng một số mã mà bạn cho rằng có thể cho phép truy cập chưa được ký. Nếu bạn không thể nghĩ về bất kỳ đoạn mã như vậy, đó là bằng chứng tốt rằng không có. –