Có một thuộc tính rất gọn gàng của các biểu thức không đổi trong C ++: đánh giá của chúng không thể có hành vi không xác định ( 7.7.4.7 ):
Biểu thức e là biểu thức hằng số cốt lõi trừ khi đánh giá e, tuân theo các quy tắc của máy trừu tượng ([intro.execut]), sẽ đánh giá một trong những điều sau đây:
...
một hoạt động sẽ có hành vi không xác định như được chỉ định trong [intro] đến [cpp] của tài liệu này [Lưu ý: bao gồm, ví dụ, tràn số nguyên đã ký ([expr.prop]), số học con trỏ nhất định ([expr.add]), chia cho số không, hoặc các hoạt động thay đổi nhất định - lưu ý cuối];
Cố gắng lưu trữ giá trị 13!
trong constexpr int
thực sự mang lại một lỗi biên dịch đẹp :
constexpr int f(int n)
{
int r = n--;
for (; n > 1; --n) r *= n;
return r;
}
int main()
{
constexpr int x = f(13);
return x;
}
Đầu ra:
9:19: error: constexpr variable 'x' must be initialized by a constant expression
constexpr int x = f(13);
^ ~~~~~
4:26: note: value 3113510400 is outside the range of representable values of type 'int'
for (; n > 1; --n) r *= n;
^
9:23: note: in call to 'f(3)'
constexpr int x = f(13);
^
1 error generated.
(BTW tại sao lỗi nói "gọi đến 'f (3)'", trong khi đó là cuộc gọi đến f (13)? ..)
Sau đó, tôi loại bỏ constexpr
khỏi x
, nhưng làm cho f
một consteval
. Theo các tài liệu :
consteval - xác định rằng một hàm là một hàm tức thời, nghĩa là, mọi lệnh gọi đến hàm phải tạo ra hằng số thời gian biên dịch
Tôi hy vọng rằng một chương trình như vậy một lần nữa sẽ gây ra lỗi biên dịch. Nhưng thay vào đó, chương trình biên dịch và chạy với UB .
Tại sao vậy?
CẬP NHẬT: Các bình luận cho rằng đây là một lỗi biên dịch. Tôi đã báo cáo nó: https://bugs.llvm.org/show_orms.cgi?id=43714
in call to 'f(3)'
- điều này thật lạ! Ví dụ. Nếu bạn đặtf(123)
clang cảnh báo vềin call to 'f(119)'
.