Tôi đang đối mặt với sự nhầm lẫn về quy tắc bí danh nghiêm ngặt C++ và các hàm ý có thể có của nó. Xét đoạn mã sau:
C/C++ bí danh nghiêm ngặt, đối tượng tồn tại và các trình biên dịch hiện đại
int main() {
int32_t a = 5;
float* f = (float*)(&a);
*f = 1.0f;
int32_t b = a; // Probably not well-defined?
float g = *f; // What about this?
}
Nhìn vào C++ thông số kỹ thuật, phần 3.10.10, về mặt kỹ thuật không ai trong số các mã được dường như vi phạm "răng cưa quy tắc" cho có:
Nếu một chương trình cố gắng truy cập vào các giá trị được lưu trữ của một đối tượng thông qua một vế trái của khác hơn là một trong các loại sau đây hành vi được unde fi định nghĩa:
... một danh sách các loại accessor đủ điều kiện ...
*f = 1.0f;
không vi phạm quy tắc vì không có quyền truy cập vào giá trị được lưu trữ, tức là tôi chỉ ghi vào bộ nhớ thông qua con trỏ. Tôi không đọc từ bộ nhớ hoặc cố gắng diễn giải một giá trị ở đây.- Dòng
int32_t b = a;
không vi phạm các quy tắc vì tôi đang truy cập thông qua loại ban đầu. - Dòng
float g = *f;
không vi phạm các quy tắc cho cùng một lý do.
Trong another thread, thành viên CortAmmon thực sự làm cho cùng một điểm trong một phản ứng, và nói thêm rằng bất kỳ hành vi không xác định có thể phát sinh thông qua viết để đối tượng sống, như trong *f = 1.0f;
, sẽ được hạch toán theo định nghĩa của tiêu chuẩn " đối tượng tồn tại "(có vẻ không quan trọng đối với các loại POD).
BAO GIỜ: Có nhiều bằng chứng bằng chứng trên internet ở trên mã sẽ tạo UB trên các trình biên dịch hiện đại. Xem ví dụ: here và here.
Luận điểm trong hầu hết các trường hợp là trình biên dịch được tự do cân nhắc &a
và f
không phải là răng cưa lẫn nhau và do đó miễn phí lên lịch lại hướng dẫn.
Câu hỏi lớn bây giờ là nếu hành vi trình biên dịch như vậy thực sự sẽ là "quá giải thích" của tiêu chuẩn.
Thời gian duy nhất mà tiêu chuẩn nói về "bí danh" cụ thể là trong chú thích ở 3.10.10, trong đó rõ ràng rằng đó là các quy tắc chi phối răng cưa.
Như tôi đã đề cập trước đó, tôi không thấy bất kỳ mã nào ở trên vi phạm tiêu chuẩn, nhưng nó sẽ được cho là bất hợp pháp bởi một số lượng lớn người (và có thể là người biên dịch).
Tôi thực sự sẽ đánh giá cao một số giải thích tại đây.
Cập nhật nhỏ:
Là thành viên BenVoigt chỉ ra một cách chính xác, int32_t
có thể không phù hợp với float
trên một số nền tảng để mã nhất định có thể là vi phạm của "lưu trữ đủ liên kết và kích thước" quy tắc. Tôi muốn nêu rõ rằng int32_t
được chọn cố ý để căn chỉnh với float
trên hầu hết các nền tảng và giả định cho câu hỏi này là các loại thực sự phù hợp.
Cập nhật nhỏ # 2:
Như một số thành viên đã chỉ ra, dòng int32_t b = a;
có lẽ là vi phạm tiêu chuẩn, mặc dù không phải với sự chắc chắn tuyệt đối. Tôi đồng ý với quan điểm đó và, không thay đổi bất kỳ khía cạnh nào của câu hỏi, yêu cầu người đọc loại trừ dòng đó khỏi tuyên bố của tôi ở trên rằng không có mã nào vi phạm tiêu chuẩn.
Viết là một dạng truy cập nhiều như đọc. –
Nếu điều đó đúng thì tiêu chuẩn sẽ nói "truy cập bộ nhớ của một đối tượng thông qua ...". Nhưng những gì nó nói là "truy cập các giá trị được lưu trữ", mà không phải là những gì mã không. – rsp1984
Trong số các vấn đề khác với mã này, bạn không bao giờ có một đối tượng kiểu 'float', bởi vì bạn không bao giờ" thu được dung lượng đủ kích thước và căn chỉnh chính xác ". 'a' có kích thước và căn chỉnh cho' int', không phải 'float', và một số nền tảng sẽ thực sự cho bạn biết (để đặt nó vui lòng). –