C++ Template für die sichere integer CASTET
Ich bin versucht, schreiben Sie ein C++ - template-Funktion, die werfen eine exception zur Laufzeit, die auf integer-überlauf in Besetzungen zwischen verschiedenen integralen Typen, mit unterschiedlichen breiten, und möglich signed/unsigned mismatch. Für diese Zwecke bin ich nicht besorgt mit der Umwandlung von Fließkomma-Typen zu integralen Typen, noch von anderen Objekt-zu-Objekt-Konvertierungen. Ich möchte dies tun, ohne zu schreiben, viel Sonderfall-code. Dies ist, was ich derzeit habe:
template< typename T, typename R > void safe_cast( const T& source, R& result )
{
//get the maximum safe value of type R
R rMax = (R) ~0;
if ( rMax < 0 ) //R is a signed type
{
//assume that we're on an 8-bit twos-compliment machine
rMax = ~( 0x80 << ( ( sizeof( R ) - 1 ) * 8 ) );
}
if ( ( source & rMax ) != source )
{
throw new IntegerOverflowException( source );
}
result = static_cast<R>( source );
}
Ist dies richtig und effizient?
EDIT: aus verschiedenen Gründen stl ist nicht verfügbar, also ich kann nicht mit std::numeric_limits, und alles, was von Boost ist raus.
- Aber Sie könnten kopieren Sie den code brauchst du von numeric_limits in Ihre eigenen Vorlagen Helfer. Ordnen Sie alles zu uint64 (oder was auch immer die maximal zulässige Größe ist) und Vergleiche dazu in diesem Typ.
- Das funktioniert vielleicht, aber man muss wirklich bewusst sein, die Lizenzbedingungen, die beim kopieren von code wie dieser. Neben potenziell Verletzung der Bedingungen, könnte man versehentlich "infizieren" Ihr code, wie ist der Fall mit der GPL. Stellen Sie sicher, dass die Lizenzen kompatibel sind, bevor Sie diese Art der Sache. Die üblichen "ich bin kein Jurist" Haftungsausschluss gilt.
- Was sind die verschiedenen Gründe, die Sie nicht verwenden können die STL?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Haben Sie versucht, SafeInt? Es ist ein cross-Plattform-Vorlage, die die integer-overflow-checks für eine Vielzahl von integer-Typen. Es ist verfügbar auf github
Können Sie die minimale und maximale sichere Werte (und eine ganze Menge andere Informationen) für jeden fundamentalen Typ auf viel elegantere Weise mit der
std::numeric_limits
Vorlage, z.B.std::numeric_limits<T>::max()
. Sie müssen<limits>
.Referenz: http://www.cplusplus.com/reference/std/limits/numeric_limits/
static_cast<From>(static_cast<To>( source ) ) != source
(im Grunde, wenn einige Informationen verloren, die cast...das funktioniert Super. Irgendwie ähnlich zu dem, was Tim schlägt vor, unten. Kein Verweis auf max/min wollen, schlägt fehl, wenn Sie sich von signed in unsigned und Umgekehrt.Ist boost eine option? Wenn ja, versuchen Sie boost::numeric_cast<>. Es erscheint zu bieten die Eigenschaften, die Sie suchen.
Ich denke, dass diese Arbeit nun, unabhängig davon, ob Sie Zweierkomplement oder nicht. Bitte ausgiebig testen, bevor Sie es verwenden. Sie geben die folgenden Ergebnisse. Jede Zeile gibt einen assertion-Fehler (nur ändern, in Ausnahmen, wie du willst)
Umsetzung. Zunächst einige Dienstprogramme zu überprüfen, für integer Ränge (Arten mit höheren Rängen werden können, enthalten die Werte der Varianten mit niedrigerem Rang, da Sie das gleiche Vorzeichen. Und einige promotion-tools, um in der Lage sein, um herauszufinden, eine gemeinsame, sichere Typ (das wird nie Ausbeute eine signierte geben, wenn ein vorzeichenloser Typ ist beteiligt, wenn das signed-Typ nicht in der Lage, speichern Sie alle Werte von unsigned eins).
Die Umwandlung von Vorlagen Gebrauch machen, um herauszufinden, für jeden Fall wenn was getan werden muss oder nicht getan.
Wie etwa:
Dann bist du nur zu prüfen, ob das Gießen gearbeitet. Stellen Sie sicher, Sie bekommen zurück, was Sie angefangen haben, und dass das Schild nicht umdrehen.
BEARBEITEN:
Da der Kommentar kam Durcheinander, hier ist es formatiert:
Den cast von int zu char funktioniert. Der cast von char auf unsigned char wirft eine Ausnahme (wie es sollte). Ich sehe kein problem hier.
Bin ich richtig in der Annahme, dass in dem Fall, dass R unterzeichnet ist, können Sie versuchen, zu füllen, rMax mit all 1s, außer für das Letzte Stück? Wenn das der Fall ist, dann sollten Sie 0x80 (1000 0000) anstelle von 0x10 (0001 0000).
Es auch nicht Aussehen, Ihre Funktion unterstützt negative zahlen für die Quelle.
Edit:
Hier ist eine leicht bearbeitete version, die ich getestet habe für die Umwandlung von ints in chars:
Edit: Fehler behoben.
betrachten Sichere Numerik bei http://rrsd.com/blincubator.com/bi_library/safe-numerics
Diese Bibliothek bietet drop-in-Ersatz für alle C primitiven integer-Typen. C Operationen, die Ergebnis-fehlerhafte Ergebnisse - einschließlich Gießen sind gefangen, sobald Sie erkannt wird.
Ich muss etwas fehlen, ist aber nicht das, was Sie wollen?:
Ich habe einen einzigen header zu süß.hpp genannt conv.hpp. Es wird testen Sie die Grenzen für alle integer-Typen und erlaubt es auch, in und aus string CASTET für integer.