Gần đây tôi đã tìm thấy một cái gì đó giống với các dòng sau:
#include <string>
// test if the extension is either .bar or .foo
bool test_extension(const std::string& ext) {
return ext == ".bar" || ".foo";
// it obviously should be
// return ext == ".bar" || ext == ".foo";
}
Các chức năng rõ ràng không làm những gì bình luận cho thấy. Nhưng đó không phải là vấn đề ở đây. Xin lưu ý rằng đây không phải là bản sao của Bạn có thể sử dụng 2 hoặc nhiều điều kiện HOẶC trong câu lệnh if không? vì tôi hoàn toàn nhận thức được làm thế nào bạn sẽ viết đúng chức năng!
Tôi bắt đầu tự hỏi làm thế nào một trình biên dịch có thể xử lý đoạn trích này. Trực giác đầu tiên của tôi sẽ là điều này sẽ được biên soạn return true;
về cơ bản. Việc đưa ví dụ vào godbolt , cho thấy cả GCC 9.2 và clang 9 đều không thực hiện tối ưu hóa này với tối ưu hóa -O2
.
Tuy nhiên, thay đổi mã thành 1
#include <string>
using namespace std::string_literals;
bool test_extension(const std::string& ext) {
return ext == ".bar"s || ".foo";
}
dường như thực hiện mánh khóe kể từ khi lắp ráp về bản chất là:
mov eax, 1
ret
Vì vậy, câu hỏi cốt lõi của tôi là: Có điều gì tôi đã bỏ lỡ không cho phép trình biên dịch thực hiện tối ưu hóa tương tự trên đoạn mã đầu tiên không?
1 Với ".foo"s
điều này thậm chí sẽ không biên dịch, vì trình biên dịch không muốn chuyển đổi std::string
thành bool
;-)
Biên tập
Đoạn mã sau đây cũng được tối ưu hóa "đúng" thành return true;
:
#include <string>
bool test_extension(const std::string& ext) {
return ".foo" || ext == ".bar";
}
operator==(string const&, string const&)
là noexcept
trong khi operator==(string const&, char const*)
không phải là? Bây giờ tôi không có thời gian để đào thêm.
foo || ext == ".bar"
, cuộc gọi được tối ưu hóa đi (xem chỉnh sửa). Điều đó có mâu thuẫn với lý thuyết của bạn không?
a || b
có nghĩa là "chỉ đánh giá biểu thức b
nếu biểu thức a
là false
". Đó là trực giao với thời gian chạy hoặc thời gian biên dịch. true || foo()
có thể được tối ưu hóa true
, ngay cả khi foo()
có tác dụng phụ, bởi vì (dù có tối ưu hóa hay không), phía bên tay phải không bao giờ được đánh giá. Nhưng foo() || true
không thể được tối ưu hóa true
trừ khi trình biên dịch có thể chứng minh rằng việc gọi foo()
không có tác dụng phụ có thể quan sát được.
xor eax,eax
ngay cả khi không có tùy chọn đó, nó gọi hàm so sánh chuỗi. Tôi không có ý tưởng gì để làm điều đó.
string::compare(const char*)
có một số tác dụng phụ mà trình biên dịch sẽ không loại bỏ (điềuoperator==(string, string)
đó không có)? Có vẻ như không thể, nhưng trình biên dịch đã xác định rằng kết quả luôn luôn đúng (cũng cómov eax, 1
ret
) ngay cả đối với đoạn đầu tiên.