Tại sao trong C ++, static_cast <unsign> của các số âm lại khác nhau nếu số đó không đổi hay không


28

Có gì quy tắc C ++ đó có nghĩa tương đươngsai ?. Được:

float f {-1.0};
bool equal = (static_cast<unsigned>(f) == static_cast<unsigned>(-1.0));

Ví dụ: https://godbolt.org/z/fcmx2P

#include <iostream>

int main() 
{
          float   f {-1.0};
    const float  cf {-1.0};

    std::cout << std::hex;
    std::cout << " f" << "=" << static_cast<unsigned>(f) << '\n';
    std::cout << "cf" << "=" << static_cast<unsigned>(cf) << '\n';

    return 0;
}

Tạo đầu ra sau:

 f=ffffffff
cf=0

6
Có một upvote: bạn đã bị bắt bởi một quy tắc quên lãng về hành vi không xác định!
Bathsheba

Những kết quả nào bạn mong đợi khi chuyển đổi một dấu phẩy âm thành dấu không dấu?
Amadeus

1
@AADEus có lẽ là gói thông thường xung quanh chúng ta nhận được khi chuyển đổi số nguyên âm. Tôi phải kiểm tra xem đó có phải là UB không vì điều đó làm tôi ngạc nhiên.
AProgrammer

1
@AADEus, đó là một trường hợp hiểu sự khác biệt. Tôi đã sửa một lỗi đánh máy vài tuần trước ... một const-float rõ ràng được chuyển thành không dấu (lỗi) và hoàn toàn quay lại ký (như một tham số chức năng đã ký). Sau đó tôi đã suy nghĩ tại sao lỗi ban đầu lại gây ra giá trị 0 trong hàm. Kiểm tra cho thấy đó là bởi vì float là const. Một dấu phẩy không phải được xác định rõ ràng thành không dấu và sau đó hoàn toàn chuyển trở lại thành đã ký không dẫn đến cùng một bahaviour - không phải là hai lần có giá trị ban đầu và dự kiến.
GreyMattR

Câu trả lời:


26

Hành vi của chương trình của bạn không được xác định : tiêu chuẩn C ++ không xác định việc chuyển đổi loại dấu phẩy động âm sang unsignedloại.

(Lưu ý hành vi bao quanh quen thuộc chỉ áp dụng cho các loại tích phân âm .)

Vì vậy, có rất ít điểm trong nỗ lực giải thích đầu ra chương trình của bạn.


1
Được xác định nếu tôi chuyển đổi float-> int-> không dấu?
Yksisarvinen

5
@Yksisarvinen: Chỉ khi floatnó nằm trong phạm vi của một int.
Bathsheba

Tôi chấp nhận rằng UB là câu trả lời đúng và vì vậy nên là kết thúc của nó ... nhưng cho rằng ... Câu trả lời của trình biên dịch có khả năng giải thích tại sao tất cả các trình biên dịch trên Compiler Explorer (clang / gcc / djgpp) tạo ra sản lượng tương đương (UB)?
GreyMattR

5
@GreyMat Nếu trình biên dịch không thể chứng minh điều đó, nó phải tạo mã để thực hiện ép kiểu. Đối với các mục đích như vậy, nó có thể sử dụng lại mã để chuyển sang loại số nguyên đã ký (kết quả sẽ chỉ là "sai" nếu truyền là UB, điều đó có nghĩa là nó không thực sự sai). Với tối ưu hóa mạnh mẽ hơn, các diễn viên sẽ không được phát ra trong trường hợp không phải là const.
Brian

@Brian, cảm ơn vì lời giải thích hữu ích đó.
GreyMattR
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.