Konvertieren eines int in ein 4-Byte-Zeichenarray (C)

77

Hey, ich möchte ein vom Benutzer eingegebenes int in 4 Bytes konvertieren, das ich einem Zeichenarray zuordne. Wie kann das gemacht werden?

Beispiel:

Konvertieren Sie Benutzereingaben von 175 in

00000000 00000000 00000000 10101111


Bei Problemen mit allen bisherigen Antworten sollte die Konvertierung von 255 zu folgenden Ergebnissen führen 0 0 0 ff:0 0 0 ffffffff

unsigned int value = 255;   

buffer[0] = (value >> 24) & 0xFF;
buffer[1] = (value >> 16) & 0xFF;
buffer[2] = (value >> 8) & 0xFF;
buffer[3] = value & 0xFF;

union {
    unsigned int integer;
    unsigned char byte[4];
} temp32bitint;

temp32bitint.integer = value;
buffer[8] = temp32bitint.byte[3];
buffer[9] = temp32bitint.byte[2];
buffer[10] = temp32bitint.byte[1];
buffer[11] = temp32bitint.byte[0];

beide ergeben 0 0 0 ffffffffstatt0 0 0 ff

Nur ein weiteres Beispiel ist 175, da die Eingabe so gedruckt wird, wie 0, 0, 0, ffffffafsie sein sollte0, 0, 0, af

Jacob Nelson
quelle
6
Wie ist Ihr Puffer [] definiert? Für ein vorzeichenloses Byte mit einem Wert größer als 127 ist das höchstwertige Bit gesetzt. Dies bedeutet eine negative Zahl, wenn ein vorzeichenbehaftetes Byte verwendet wird. Ihr FFFFFFFF sieht aus wie eine vorzeichenerweiterte Interpretation eines 0xFF-Bytes.
Blastfurnace
Sie sollten das Format% hhx verwenden, um Ihre Zahlen zu drucken.
Jens Gustedt
..aber beachten Sie, dass dies %hhxeine C99-Ergänzung ist.
Café
1
Nit: Sie haben keine Garantie dafür, dass 4 Bytes notwendig und ausreichend sind, um ein int zu halten. Sie benötigen sizeof (int)Bytes.
PMG
Für diejenigen, die auf diesen Beitrag stoßen könnten: Die einzig richtige Lösung besteht darin, die Bitverschiebung für vorzeichenlose Typen wie in der akzeptierten Antwort zu verwenden. Sie können das lesen und dort anhalten. Es ist sowohl die schnellste als auch die tragbarste Version. memcpybei vorzeichenlosen Typen ist in Ordnung, wenn alle Typen vorzeichenlos sind und die Endianess berücksichtigt wurde. Gewerkschaftslösungen sind nicht in Ordnung, sie sind nicht portierbar - warum nicht portierbaren Code schreiben, wenn Sie mit dem gleichen Aufwand portablen Code erhalten können? Zeigerarithmetische Lösungen sind nicht in Ordnung, sie sind möglicherweise langsam, definitiv nicht portierbar und rufen häufig schlecht spezifiziertes Verhalten hervor.
Lundin

Antworten:

150

Der tragbare Weg, dies zu tun (um sicherzustellen, dass Sie 0x00 0x00 0x00 0xafüberall hinkommen ), besteht darin, Schichten zu verwenden:

unsigned char bytes[4];
unsigned long n = 175;

bytes[0] = (n >> 24) & 0xFF;
bytes[1] = (n >> 16) & 0xFF;
bytes[2] = (n >> 8) & 0xFF;
bytes[3] = n & 0xFF;

Die Methoden verwenden Gewerkschaften und memcpy()erhalten auf verschiedenen Maschinen ein unterschiedliches Ergebnis.


Das Problem, das Sie haben, ist eher das Drucken als die Konvertierung. Ich nehme an, Sie verwenden chareher als unsigned charund Sie verwenden eine Zeile wie diese, um sie zu drucken:

printf("%x %x %x %x\n", bytes[0], bytes[1], bytes[2], bytes[3]);

Wenn Typen schmaler sind als intübergeben printf, werden sie heraufgestuft int(oder unsigned int, wenn intnicht alle Werte des ursprünglichen Typs gespeichert werden können). Wenn chares auf Ihrer Plattform signiert ist, 0xffpasst es wahrscheinlich nicht in den Bereich dieses Typs und wird stattdessen auf -1 gesetzt (was die Darstellung 0xffauf einem 2s-Komplement-Computer hat).

-1 wird zu einem befördert intund hat die Darstellung 0xffffffffals ein intauf Ihrem Computer, und das sehen Sie.

Ihre Lösung besteht darin, entweder tatsächlich zu verwenden unsigned charoder unsigned charin der printfAnweisung zu verwenden:

printf("%x %x %x %x\n", (unsigned char)bytes[0],
                        (unsigned char)bytes[1],
                        (unsigned char)bytes[2],
                        (unsigned char)bytes[3]);
caf
quelle
Ich habe meine Frage bearbeitet, damit Sie das Problem sehen können, das ich mit Ihrer Lösung habe.
Jacob Nelson
2
@jacobnlsn: Es ist ein Problem mit der Art und Weise, wie Sie es drucken, siehe Update.
Café
Könnten Sie das '& 0xFF;' ein bisschen bitte? Was macht dieser Code?
ZerOne
1
ZerOne: &ist bitweises UND, was ein Ergebnis ergibt, bei dem jedes Bit 1 ist, wenn die entsprechenden Bits in beiden Operanden 1 sind. a & 0xFFDann ergibt sich ein Ergebnis, bei dem die niedrigsten 8 Bits mit den niedrigsten 8 Bits identisch asind und die verbleibenden Bits alle Null.
Café
4
@rem: Obwohl ungewöhnlich, chardarf es breiter als 8 Bit sein (einige DSP-Programmierumgebungen weisen dies auf), sodass die Maske nur sicherstellt, dass in diesem Fall das Richtige passiert. Für den allgemeinen Fall wird es trotzdem optimiert.
Café
15

Möchten Sie die einzelnen Bytes eines 32-Bit-Int adressieren? Eine mögliche Methode ist eine Vereinigung:

union
{
    unsigned int integer;
    unsigned char byte[4];
} foo;

int main()
{
    foo.integer = 123456789;
    printf("%u %u %u %u\n", foo.byte[3], foo.byte[2], foo.byte[1], foo.byte[0]);
}

Hinweis: Der Druck wurde korrigiert, um vorzeichenlose Werte wiederzugeben.

Hochofen
quelle
Ich habe meine Frage bearbeitet, damit Sie das Problem sehen können, das ich mit Ihrer Lösung habe.
Jacob Nelson
5
Ich würde uint32_t anstelle von int schreiben, um mir keine Sorgen um 32- oder 64-Bit-Maschinen zu machen.
Tadeusz A. Kadłubowski
1
Stellen Sie sicher, dass Sie nicht mit undefiniertem Verhalten zu tun haben. stackoverflow.com/questions/11639947
bzeaman
7

In Ihrer Frage haben Sie angegeben, dass Sie eine Benutzereingabe von 175 in konvertieren möchten. Dies 00000000 00000000 00000000 10101111ist eine Big-Endian- Bytereihenfolge, die auch als Netzwerkbyte-Reihenfolge bezeichnet wird .

Eine meist portable Möglichkeit, Ihre vorzeichenlose Ganzzahl in ein vorzeichenloses Big-Endian-Zeichen-Array zu konvertieren, wie Sie aus dem von Ihnen angegebenen Beispiel "175" vorgeschlagen haben, besteht darin, die htonl()Funktion von C (im Header <arpa/inet.h>auf Linux-Systemen definiert) zu verwenden, um Ihr vorzeichenloses int in zu konvertieren Big-Endian-Bytereihenfolge, dann verwenden Sie memcpy()(definiert im Header <string.h>für C, <cstring>für C ++), um die Bytes in Ihr char-Array (oder vorzeichenloses char-Array) zu kopieren.

Die htonl()Funktion verwendet eine vorzeichenlose 32-Bit-Ganzzahl als Argument (im Gegensatz zu htons()einer vorzeichenlosen 16-Bit-Ganzzahl) und konvertiert sie in die Netzwerkbyte-Reihenfolge aus der Host-Byte-Reihenfolge (daher das Akronym Host TO Network Long,). versus Host TO Network Short for htons), wobei das Ergebnis als vorzeichenlose 32-Bit-Ganzzahl zurückgegeben wird. Der Zweck dieser Funktionsfamilie besteht darin, sicherzustellen, dass die gesamte Netzwerkkommunikation in der Big-Endian-Bytereihenfolge erfolgt, sodass alle Maschinen über einen Socket ohne Probleme mit der Bytereihenfolge miteinander kommunizieren können. (Nebenbei bemerkt, für Big-Endian - Maschinen, die htonl(), htons(), ntohl()undntohs() Funktionen werden im Allgemeinen nur als "no op" kompiliert, da die Bytes nicht umgedreht werden müssen, bevor sie gesendet oder von einem Socket empfangen werden, da sie bereits in der richtigen Bytereihenfolge vorliegen.

Hier ist der Code:

#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>

int main() {
    unsigned int number = 175;

    unsigned int number2 = htonl(number);
    char numberStr[4];
    memcpy(numberStr, &number2, 4);

    printf("%x %x %x %x\n", numberStr[0], numberStr[1], numberStr[2], numberStr[3]);

    return 0;
}

Beachten Sie, dass Sie, wie im Café erwähnt, die Zeichen mit dem Formatbezeichner von printf als vorzeichenlose Zeichen drucken müssen %x.

Der obige Code wird 0 0 0 afauf meinem Computer gedruckt (einem x86_64-Computer, der eine kleine Endian-Bytereihenfolge verwendet), der für 175 hexadezimal ist.

villapx
quelle
2

Du kannst es versuchen:

void CopyInt(int value, char* buffer) {
  memcpy(buffer, (void*)value, sizeof(int));
}
Jbernadas
quelle
2
Sie sollten nicht charfür Bytes verwenden, verwenden uint8_t. (void*)valueist einfach falsch, sollte sein &value.
Lundin
1

Warum benötigen Sie eine Zwischenbesetzung, um * in C ++ ungültig zu machen? Da cpp keine direkte Konvertierung zwischen Zeigern zulässt, müssen Sie reinterpret_cast oder eine Umwandlung verwenden, um * zu stornieren.

Luiz Felipe
quelle
0
int a = 1;
char * c = (char*)(&a); //In C++ should be intermediate cst to void*
Gandjustas
quelle
3
Warum benötigen Sie eine Zwischenbesetzung void *in C ++?
Am
-1

Das Problem bei der Konvertierung (der Grund, warum Sie am Ende ein ffffff erhalten) ist, dass Ihre hexadezimale Ganzzahl (mit der Sie den Operator & binary verwenden) als signiert interpretiert wird. Wenn Sie es in eine vorzeichenlose Ganzzahl umwandeln, ist alles in Ordnung.

Enusi
quelle
-1

An intist äquivalent zu uint32_tund charzu uint8_t.

Ich werde zeigen, wie ich die Client-Server-Kommunikation aufgelöst, die tatsächliche Zeit (4 Byte, formatiert in der Unix-Epoche) in einem 1-Bit-Array gesendet und dann auf der anderen Seite neu erstellt habe. (Hinweis: Das Protokoll sollte 1024 Bytes senden.)

  • Client-Seite

    uint8_t message[1024];
    uint32_t t = time(NULL);
    
    uint8_t watch[4] = { t & 255, (t >> 8) & 255, (t >> 16) & 255, (t >> 
    24) & 255 };
    
    message[0] = watch[0];
    message[1] = watch[1];
    message[2] = watch[2];
    message[3] = watch[3];
    send(socket, message, 1024, 0);
    
  • Serverseite

    uint8_t res[1024];
    uint32_t date;
    
    recv(socket, res, 1024, 0);
    
    date = res[0] + (res[1] << 8) + (res[2] << 16) + (res[3] << 24);
    
    printf("Received message from client %d sent at %d\n", socket, date);
    

Ich hoffe es hilft.

Franco Méndez
quelle
-2

Das Problem tritt auf, da vorzeichenloses Zeichen eine 4-Byte-Zahl ist, keine 1-Byte-Zahl, wie viele denken. Ändern Sie sie daher in

union {
unsigned int integer;
char byte[4];
} temp32bitint;

und während des Druckens gegossen, um zu verhindern, dass auf 'int' hochgestuft wird (was C standardmäßig tut)

printf("%u, %u \n", (unsigned char)Buffer[0], (unsigned char)Buffer[1]);
Dr. Sahib
quelle
-2

Sie können einfach memcpywie folgt verwenden:

unsigned int value = 255;
char bytes[4] = {0, 0, 0, 0};
memcpy(bytes, &value, 4);
HomDhi
quelle