2016-07-16 5 views
-4

Ich versuche, eine ganze Zahl von Daten aus/dev/random zu ziehen. Der folgende Code funktioniert. Ich versuche zu verstehen, warum ich den size_t-Typ für die endgültige Ausgabe verwenden muss, um Genauigkeitsverluste zu vermeiden. Siehe die Kommentare im Code.Verlust der Genauigkeit von 4 Byte Char-Array zu int?

Ich dachte, dass das Problem vielleicht war, dass die .read-Methode eine Art von Padding wie ein Null-Beendigungszeichen hinzufügte. Ich habe versucht, die Länge auf 3 zu setzen, um das zu vermeiden, aber es schien keine Rolle zu spielen. Ich bin froh, dass ich herausgefunden habe, wie ich das lösen kann, aber ich würde gerne verstehen, warum ich musste.

size_t getSeed() 
{ 
    std::ifstream rnd ("/dev/random", std::ios::binary); 
    if(rnd.is_open()) 
    { 
     int len = sizeof(int);    // 4 bytes 
     char* blk = new char [len]; 
     rnd.read (blk, len);    // 8 bytes? 
     rnd.close(); 
     size_t out = (size_t)*blk;   // loss of precision with int 
     delete[] blk; 
     return out; 
    } 
    else 
    { 
     return 0; 
    } 
} 
+0

@ mreff555 Was hast du gerade getan? – LogicStuff

+0

LogicStuff, was meinst du? Paul R., was wäre der richtige Weg, um diese Konvertierung zu machen? – mreff555

+1

Auch wenn es richtig war (du machst nur das erste "char"), warum würdest du es bearbeiten? – LogicStuff

Antwort

1

Ich kann nicht undrstand warum Sie 4 char im Binär-Modus lesen und sie dann zu int speichern, das heißt zu size_t. Es wäre einfacher, aus dem Strom zu size_t out direkt zu lesen:

size_t out; 
rnd.read (&out, sizeof(out)); 

Aber, wenn es nur ein Experiment ich Ihnen einige Varianten vorschlagen möge 4 char in eine int 32-Bit zu packen.

Es ist die erste (C-Stil) Option mit union:

#include <cstdint> 

union ConversionUnion 
{ 
    int32_t dint; 
    char dchar[4]; 
}; 

int32_t getSeed() 
{ 
    std::ifstream rnds ("/dev/random", std::ios::binary); 
    ConversionUnion conv; 
    if(rnds.is_open()) 
    { 
     rnds.read (conv.dchar, sizeof(int32_t)); 
     rnds.close(); 
     return conv.dint; 
    } 
    else 
    { 
     return 0; 
    } 
} 

Und wenn Sie einfach Ihren Code zu beheben, versuchen Sie Änderungslinie

size_t out = (size_t)*blk; 

Linie (diese auch eher ist C als C++)

Denken Sie auch über Lösung, die für 4 Zahlen war (nicht Array) - here. Aber der gleiche Ansatz kann für Array verwendet werden:

int32_t result = 0; 
    for(int i = 0; i < 4; i++) // or 
    // for(int i = 3; i > 0; i--) // for reverse order of bytes if needed 
    { 
     result <<= 8; 
     result |= blk[i]; 
    } 
+0

Perfekt. Union klingt nach dem, wonach ich gesucht habe. Um Ihre erste Sorge zu beantworten, war der Grund, warum ich nur 4 Bytes gelesen habe, dass ich nur versuchen würde, 4 Bytes auszugeben. Das Problem war jedoch, dass die Variable blk auf 8 Bytes anschwellen würde. – mreff555

+0

Für 64-Bit- und 8-Zeichen ändern Sie die Union auf 'union ConversionUnion { int64_t dint; char dchar [8]; }; 'und benutze' sizeof (int64_t) 'als zweites Argument von' read' – VolAnd

+1

Bessere 'union ConversionUnion {int64_t dint; char dchar [Größe von (dint)]; }; 'und' rnds.read (conv.dchar, sizeof (conv.dchar)); ' – LogicStuff