2015-09-01 10 views
5

Ich habe folgendes einfaches Programm, das eine Vereinigung verwendet zwischen einer 64-Bit-Ganzzahl und der entsprechenden Byte-Array zu konvertieren:C/C++ Konvertieren eines 64-Bit-Integer-Array verkohlen

union u 
{ 
    uint64_t ui; 
    char c[sizeof(uint64_t)]; 
}; 

int main(int argc, char *argv[]) 
{ 
    u test; 
    test.ui = 0xabcdefLL; 
    for(unsigned int idx = 0; idx < sizeof(uint64_t); idx++) 
    { 
     cout << "test.c[" << idx << "] = 0x" << hex << +test.c[idx] << endl; 
    } 
    return 0; 
} 

was ich als Ausgang würde erwarten ist:

test.c[0] = 0xef 
test.c[1] = 0xcd 
test.c[2] = 0xab 
test.c[3] = 0x89 
test.c[4] = 0x67 
test.c[5] = 0x45 
test.c[6] = 0x23 
test.c[7] = 0x1 

Aber was ich eigentlich:

test.c[0] = 0xffffffef 
test.c[1] = 0xffffffcd 
test.c[2] = 0xffffffab 
test.c[3] = 0xffffff89 
test.c[4] = 0x67 
test.c[5] = 0x45 
test.c[6] = 0x23 
test.c[7] = 0x1 

ich dies auf Ubuntu LTS 14.04 mit GCC zu sehen bin.

Ich habe schon seit einiger Zeit versucht, mich damit zu beschäftigen. Warum werden die ersten 4 Elemente des char-Arrays als 32-Bit-Ganzzahlen angezeigt, denen 0xffffff vorangestellt ist? Und warum nur die ersten 4, warum nicht alle?
Interessanterweise werden die richtigen Werte geschrieben, wenn ich das Array verwende, um in einen Stream zu schreiben (was der ursprüngliche Zweck der ganzen Sache war). Aber das Vergleichen des Array-Zeichens durch char führt offensichtlich zu Problemen, da die ersten 4 Zeichen nicht gleich 0xef, 0xcd usw. sind.

+0

umgewandelt als '(char *)' und dann lesen 4 Bytes ...? – SteJ

+0

Keine Änderung. Außerdem kann ich das Zeichen immer mit 0x000000ff maskieren, um die erwarteten Werte zu erhalten. Ich bin nur an dem Grund interessiert, der zu diesem Verhalten geführt hat. – tickferno

+2

Anscheinend hat Ihre Implementierung Zeichen signiert. Normale Integer-Promotion wird vorzeichenerweitert. – ewd

Antwort

3

Die Verwendung von char ist nicht richtig, da es signed oder unsigned sein könnte. Verwenden Sie unsigned char.

union u 
{ 
    uint64_t ui; 
    unsigned char c[sizeof(uint64_t)]; 
}; 
+0

Das löst es. Das Problem ist jetzt, dass das Schreiben des Arrays in einen Stream Fehler verursacht, da die Streams nur 'char *' akzeptieren und nicht 'unsigned char *' und ich nicht wirklich gerne "reinterpret_cast" die ganze Zeit verwende ... – tickferno

+1

@tickferno, Wenn Sie Hilfe benötigen, stellen Sie bitte eine weitere Frage, die sich speziell mit dem Streaming-Problem befasst. –

0

Es ist unsigned char vs signed char und seine Casting

1

Verwenden Sie entweder unsigned char auf ganzzahlige oder test.c[idx] & 0xff verwenden Vorzeichenerweiterung zu vermeiden, wenn ein char value > 0x7f in int umgewandelt wird.

0

unären und bewirkt, dass die zu einer charint (integral Förderung) gefördert werden. Da Sie Zeichen signiert haben, wird der Wert als solcher verwendet und die anderen Bytes spiegeln das wider.

Es ist nicht wahr, dass nur die vier Intars sind, sie alle sind. Sie sehen es einfach nicht von der Repräsentation, da die führenden Nullen nicht angezeigt werden.

Verwenden Sie entweder unsigned char s oder & 0xff für die Werbung, um das gewünschte Ergebnis zu erhalten.

2

char wird zu einem int wegen des vorangestellten unären + Operators befördert. . Da Ihre charssigned sind, wird jedes Element mit dem höchsten Wert, das auf 1 gesetzt ist, als negative Zahl interpretiert und zu einer Ganzzahl mit demselben negativen Wert hochgestuft. Es gibt ein paar verschiedene Möglichkeiten, dieses Problem zu lösen:

  1. Drop the +: ... << test.c[idx] << .... Dies kann das Zeichen als Zeichen statt als Zahl ausgeben, ist also wahrscheinlich keine gute Lösung.
  2. Deklarieren Sie c als unsigned char. Dies wird es zu einem unsigned int fördern.
  3. gegossen Explizit +test.c[idx] bevor es übergeben wird: ... << +test.c[idx] & 0xFF << ...: ... << (unsigned char)(+test.c[idx]) << ...
  4. das obere Bytes der ganzen Zahl auf Nullen unter Verwendung von binären & einstellen.Dies zeigt nur das niederwertigste Byte an, egal wie das char befördert wird.
+0

Char wird im Operator << nicht gefördert, es liegt an dem Operator unary +. Dies kann leicht erkannt werden, wenn Sie das unäre + aus dem Code löschen. –

+0

Das Löschen des unären + Operators gibt das Zeichen "direkt" aus, aber ich bin an ihrem tatsächlichen Hex-Wert interessiert (der hex-Operator hilft sonst nicht). Auch das Folgende schlägt fehl: 'test.c [0] == 0xef' – tickferno

+0

Guter Anruf. Entsprechend bearbeitet. –