Είναι ασφαλές να reinterpret_cast ένας ακέραιος αριθμός για float;

Είναι ασφαλές να reinterpret_cast ένας ακέραιος αριθμός για float;

Λοιπόν, static_cast είναι "ασφαλές" και έχει καθορισμένη συμπεριφορά, αλλά μάλλον δεν είναι αυτό που χρειάζεστε. Η μετατροπή μιας ακέραιης τιμής σε τύπο κινητής απλώς θα προσπαθήσει να αναπαραστήσει την ίδια ακέραια τιμή στον τύπο κινητής υποδιαστολής στόχου. Δηλ. 5 τύπου int θα μετατραπεί σε 5.0 τύπου float (υποθέτοντας ότι μπορεί να αναπαρασταθεί με ακρίβεια).

Αυτό που φαίνεται να κάνετε είναι να δημιουργήσετε την αναπαράσταση αντικειμένου του float τιμή σε ένα κομμάτι μνήμης που δηλώνεται ως Uint32 μεταβλητός. Για να παραχθεί το προκύπτον float τιμή που πρέπει να επαναερμηνεύσετε αυτή η μνήμη. Αυτό θα επιτευχθεί με το reinterpret_cast

assert(sizeof(float) == sizeof val);
return reinterpret_cast<float &>( val );

ή, αν προτιμάτε, μια έκδοση δείκτη του ίδιου πράγματος

assert(sizeof(float) == sizeof val);
return *reinterpret_cast<float *>( &val );

Αν και αυτού του είδους η λογοπαίγνια δεν είναι εγγυημένο ότι θα λειτουργήσει σε έναν μεταγλωττιστή που ακολουθεί τη σημασιολογία αυστηρής αλυσοποίησης. Μια άλλη προσέγγιση θα ήταν να το κάνετε αυτό

float f;

assert(sizeof f == sizeof val);
memcpy(&f, &val, sizeof f);

return f;

Ή ίσως μπορείτε να χρησιμοποιήσετε το γνωστό union hack για να εφαρμόσετε την επανερμηνεία της μνήμης. Αυτό είναι τυπικά παράνομο στην C++ (απροσδιόριστη συμπεριφορά), που σημαίνει ότι αυτή η μέθοδος μπορεί να χρησιμοποιηθεί μόνο με ορισμένες υλοποιήσεις που την υποστηρίζουν ως επέκταση

assert(sizeof(float) == sizeof(Uint32));

union {
  Uint32 val; 
  float f;
} u = { val };

return u.f;

Εν ολίγοις, είναι λάθος. Μεταφέρετε έναν ακέραιο σε ένα float και θα ερμηνευτεί από τον μεταγλωττιστή ως ακέραιος εκείνη τη στιγμή. Η λύση της ένωσης που παρουσιάστηκε παραπάνω λειτουργεί.

Ένας άλλος τρόπος για να κάνετε το ίδιο πράγμα όπως η ένωση είναι να χρησιμοποιήσετε αυτό:

return *reinterpret_cast<float*>( &val );

Είναι εξίσου ασφαλές/μη ασφαλές με την παραπάνω λύση ένωσης και σίγουρα θα συνιστούσα ένα assert για να βεβαιωθείτε ότι το float έχει το ίδιο μέγεθος με το int.

Θα προειδοποιούσα επίσης ότι ΥΠΑΡΧΟΥΝ μορφές κινητής υποδιαστολής που δεν είναι συμβατές με το IEEE-754 ή το IEEE-854 (αυτά τα δύο πρότυπα έχουν την ίδια μορφή για αριθμούς κινητής υποδιαστολής, δεν είμαι απολύτως σίγουρος ποια είναι η διαφορά στις λεπτομέρειες, για να είμαι ειλικρινής). Έτσι, εάν έχετε έναν υπολογιστή που χρησιμοποιεί διαφορετική μορφή κινητής υποδιαστολής, θα πέσει. Δεν είμαι σίγουρος αν υπάρχει κάποιος τρόπος να το ελέγξω αυτό, εκτός από το ότι ίσως έχουμε αποθηκευμένο κάπου ένα κονσερβοποιημένο σύνολο byte, μαζί με τις αναμενόμενες τιμές στο float, μετατρέψτε τις τιμές και δείτε αν εμφανίζεται "σωστά".