Wie können Bytes in einem Char-Array ganze Zahlen darstellen?

Nehmen wir also an, ich habe ein Char-Array, das ich aus einer Binärdatei lese (wie eine ext2-formatierte Dateisystem-Image-Datei).

Jetzt muss ich die Ganzzahl ab Offset-Byte 1024 lesen (<- das ist der Offset vom Beginn der Daten). Gibt es einen sauberen Weg, es zu tun. Die Ganzzahl kann eine beliebige Zahl sein. Ich glaube also, dass es auf meinem System (x86-64) in einer ganzzahligen Größe von 4 Byte dargestellt werden kann.

Ich glaube, ich muss strtol wie folgt verwenden:

/* Convert the provided value to a decimal long */
char *eptr=malloc(4);// 4 bytes becuase sizeof int is 4 bytes
....
int valread=read(fd,eptr,4);//fd is to ext2 formatted image file (from file system)
result = strtol(eptr, &v, 10);

Das Obige ist long, also ist dies die Zahl, die eine 32-Bit-Ganzzahl darstellt?

Sollte eptr nullterminiert sein?

Ist das richtig oder nicht?

🤔 А знаете ли вы, что...
C оставался популярным и актуальным языком программирования на протяжении многих десятилетий.


1
58
2

Antworten:

Im Fall von strtol ist es möglicherweise einfacher, dem Code zu folgen. Hier also eine sehr vereinfachte strtol Art von Funktion:

int string_to_int(const char *string)
{
    // The integer value we construct and return
    int value = 0;

    // Loop over all the characters in the string, one by one,
    // until the string null-terminator is reached
    for (unsigned i = 0; string[i] != '\0'; ++i)
    {
        // Get the current character
        char c = string[i];

        // Convert the digit character to its corresponding numeric value
        int c_value = c - '0';

        // Add the characters numeric value to the current value
        value = (value * 10) + c_value;

        // Note the multiplication with 10: That's because decimal numbers are base 10
    }

    // Now the string have been converted to its decimal integer value, return it
    return value;
}

Wenn wir es mit der Zeichenfolge "123" aufrufen und die Schleife aufrollen, passiert Folgendes:

// First iteration
char c = string[0];  // c = '1'
int c_value = c - '0';  // c_value = 1
value = (value * 10) + c_value;  // value = (0 * 10) + 1 = 0 + 1 = 1

// Second iteration
char c = string[0];  // c = '2'
int c_value = c - '0';  // c_value = 2
value = (value * 10) + c_value;  // value = (1 * 10) + 2 = 10 + 2 = 12

// Third iteration
char c = string[0];  // c = '3'
int c_value = c - '0';  // c_value = 3
value = (value * 10) + c_value;  // value = (12 * 10) + 3 = 120 + 3 = 123

In der vierten Iteration erreichen wir den String-Nullterminator und die Schleife endet damit, dass value gleich dem int-Wert 123 ist.

Ich hoffe, dies macht es ein wenig klarer, wie die Umwandlung von Zeichenfolgen in Zahlen funktioniert.


Während das Obige für Zeichenfolgen gilt, sollten Sie int nicht aufrufen, wenn Sie die rohen Binärbits eines vorhandenen strtol-Werts lesen, da die Daten keine Zeichenfolge sind.

Stattdessen interpretieren Sie die vier Bytes im Grunde als einen einzigen 32-Bit-Wert.

Leider ist es nicht einfach zu erklären, wie diese Bits interpretiert werden, ohne ein oder zwei Dinge über Endianität zu wissen.

Endianness ist, wie die Bytes geordnet sind, um den ganzzahligen Wert zu bilden. Unter Verwendung der (hexadezimalen) Zahl 0x01020304 können sie entweder als 0x01, 0x02, 0x03 und 0x04 gespeichert werden (dies wird Big-Endian genannt); Oder als 0x04, 0x03, 0x02 und 0x01 (dies wird Little-Endian genannt).

Angenommen, Sie haben auf einem Little-Endian-System (Ihrem normalen PC-ähnlichen System) ein Array wie dieses:

char bytes[4] = { 0x04, 0x03, 0x02, 0x01 };

dann könntest du es in ein int kopieren:

int value;
memcpy(&value, bytes, 4);

und das macht die Variable intvalue gleich 0x01020304.


Gelöst

I have char array that I read from binary file (like ext2 formatted filesystem image file).

Öffnen Sie die Datei im Binärmodus

const char *file_name = ...;
FILE *infile = fopen(file_name, "rb");  // b is for binary
if (infile == NULL) {
  fprintf(stderr, "Unable to open file <%s>.\n", file_name);
  exit(1);
}

I need to read integer starting at offset byte 1024 ...

long offset = 1024; 
if (fseek(infile, offset, SEEK_SET)) {
  fprintf(stderr, "Unable to seek to %ld.\n", offset);
  exit(1);
} 

So I believe can be represented in integer size of 4 byte on my system

Anstatt int zu verwenden, das sich von 4-Bytes unterscheiden kann, ziehen Sie int32_t von <stdint.h> in Betracht.

int32_t data4;
if (fread(&data4, sizeof data4, 1, infile) != 1) {
  fprintf(stderr, "Unable to read data.\n");
  exit(1);
} 

Konto für Endian.

Da die Dateidaten Little-Endian sind, konvertieren Sie sie in natives Endian. Siehe #include <endian.h>.

data4 = le32toh(data4);

Aufräumen, wenn Sie fertig sind

// Use data4

fclose(infile);

believe I need to use strtol like

Nein. strtol() untersucht ein Schnur und gibt ein long zurück. Dateidaten sind binär und keine Zeichenkette.