เหตุใดใน C ++ static_cast <unsigned> ของจำนวนลบจึงแตกต่างกันถ้าจำนวนนั้นเป็นค่าคงที่หรือไม่


28

กฎ C ++ ที่มีความหมายเท่าเทียมกันคือเท็จ ? ได้รับ:

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

เช่น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;
}

สร้างเอาต์พุตต่อไปนี้:

 f=ffffffff
cf=0

6
มี upvote: คุณถูกจับโดยกฎที่มักถูกลืมเกี่ยวกับพฤติกรรมที่ไม่ได้กำหนด!
Bathsheba

ผลลัพธ์ใดที่คุณคาดหวังว่าจะแปลงทุ่นเชิงลบเป็นสัญญาณที่ไม่ได้ลงชื่อ
อะมาดิอุส

1
@Ajustus อาจเป็นเรื่องปกติที่เราได้รับเมื่อแปลงจำนวนเต็มลบ ฉันต้องตรวจสอบว่ามันเป็น UB เพราะนั่นทำให้ฉันประหลาดใจ
AProgrammer

1
@Amadeus มันเป็นกรณีที่เข้าใจความแตกต่าง ฉันแก้ไขข้อผิดพลาดการพิมพ์ไม่กี่สัปดาห์ที่ผ่านมา ... const-float ถูกบล็อกอย่างชัดเจนเพื่อไม่ได้ลงนาม (ข้อผิดพลาด) และโดยปริยายกลับสู่การเซ็นชื่อ (เป็นพารามิเตอร์ฟังก์ชันที่ลงนามแล้ว) ในภายหลังฉันได้ไตร่ตรองว่าเหตุใดข้อผิดพลาดดั้งเดิมทำให้เกิดค่าศูนย์ในฟังก์ชัน การทดสอบแสดงให้เห็นว่าเป็นเพราะการลอยตัวเป็นค่าคงที่ การลอยตัวแบบไม่ใช่ const ที่โยนลงมาอย่างไม่ระบุชื่อและจากนั้นการโยนกลับไปที่การเซ็นชื่อนั้นไม่ได้ส่งผลให้เกิดผลเหมือนกัน - ไม่ใช่แบบสองครั้งที่มีค่าคงที่เดิมและคาดหวัง
GreyMattR

คำตอบ:


26

ลักษณะการทำงานของโปรแกรมของคุณไม่ได้ถูกกำหนด : มาตรฐาน C ++ ไม่ได้กำหนดการแปลงชนิดทศนิยมที่เป็นลบให้เป็นunsignedประเภท

(โปรดทราบว่าพฤติกรรมการล้อมรอบที่คุ้นเคยใช้เฉพาะกับประเภทอินทิกรัลเชิงลบเท่านั้น)

ดังนั้นจึงมีจุดเล็กน้อยในการพยายามอธิบายผลลัพธ์ของโปรแกรมของคุณ


1
มันถูกกำหนดหรือไม่ถ้าฉันแปลง float-> int-> unsigned แทน?
Yksisarvinen

5
@Yksisarvinen: เฉพาะถ้าอยู่ในช่วงของนั้นfloat int
Bathsheba

ฉันยอมรับว่า UB เป็นคำตอบที่ถูกต้องและควรเป็นจุดจบของมัน ... แต่เนื่องจากว่า ... คำตอบของผู้รวบรวมคอมไพเลอร์ที่น่าจะอธิบายได้ว่าทำไมคอมไพเลอร์ทั้งหมดใน Compiler Explorer (เสียงดังกราว / gcc / djgpp) เอาท์พุทเทียบเท่า (UB)?
GreyMattR

5
@GreyMattR หากคอมไพเลอร์สามารถพิสูจน์ได้ว่าค่านั้นมีค่าเป็นลบ ณ เวลาที่ใช้ในการร่ายจากนั้นก็สามารถทิ้งผลของการร่ายไม่กำหนดค่าเริ่มต้นหรือตั้งค่าเป็นศูนย์หรืออะไรก็ตามที่มันต้องการจะทำ หากคอมไพเลอร์ไม่สามารถพิสูจน์ได้มันจะต้องสร้างรหัสเพื่อทำการส่ง สำหรับวัตถุประสงค์ดังกล่าวสามารถใช้รหัสซ้ำเพื่อส่งไปยังประเภทจำนวนเต็มที่ลงนามแล้ว (ผลลัพธ์จะเป็น "ผิด" หากการส่งเป็น UB ซึ่งหมายความว่าไม่ผิดจริง ๆ ) ด้วยการเพิ่มประสิทธิภาพที่ก้าวร้าวมากขึ้นนักแสดงจะไม่ถูกปล่อยออกมาในกรณีที่ไม่ใช่ const เช่นกัน
Brian

@Brian ขอบคุณสำหรับคำอธิบายที่เป็นประโยชน์
GreyMattR
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.