Forum: Mikrocontroller und Digitale Elektronik Einlesen einer Hex Zahl von stdin


von Isi S. (ischmtt)


Lesenswert?

Hallo zusammen,

ich bin gerade dabei, ein Programm zu schreiben, in dem eine Adresse in 
Hexadezimal von einem PC gesendet und weiter verarbeitet werden soll. 
Die Adresse lese ich mit fgets ein. Das Problem ist, dass der Wert 0x00 
auch in der Mitte der Adressen vorkommt und nicht nur am Ende z.B. D3 88 
00 FF FF 01 00. Die Adresse wird nur bis zu 88 eingelesen, 
schätzungsweise da die erste 00 als Ende angesehen wird. Gibt es eine 
Möglichkeit die komplette Adresse einzulesen? Programmiert wird in der 
Sprache C.

#include <stdio.h>
#include <string.h>

int main(){
    char adresse[8];
    fgets(adresse, 8, stdin);
    printf("%s", adresse);

    fflush(stdin);
}

Danke schonmal für die Antworten.

: Bearbeitet durch User
von Steve van de Grens (roehrmond)


Lesenswert?

fgets() dient zum Einlesen von Zeichenketten.

Du willst aber binäre Daten lesen, wo jedes byte einen beliebigen Wert 
haben kann. Dazu ist die Funktion fread() gedacht.

https://www.tutorialspoint.com/c_standard_library/c_function_fread.htm

> printf("%s", adresse);

%s dient zur Ausgabe von Zeichenketten. Deine Adresse ist aber keine 
Zeichenkette, sondern eine Folge von Bytes. Gebe die 8 Bytes so aus:
1
for (int i=0; i<8 i++) {
2
  printf("%02x", adresse[i]);
3
}

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

An den String ein CR anhängen und darauf testen.
Bei fread muss die Länge der Zeichenkette vorher bekannt sein.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Isi S. schrieb:
> in dem eine Adresse in Hexadezimal von einem PC gesendet und weiter
> verarbeitet werden soll.
Mein Tipp: nimm ASCII-Zeichenketten, dann kannst du auch die üblichen 
ASCII-Steuerzeichen für Textanfang (STX) und Textende (ETX) oder 
Zeilenende (wie z.B. 0x0a und 0x0d für CR/LF) verwenden.
- 
https://www.itwissen.info/Textende-end-of-text-control-character-ETX.html

Und zusätzlicher Bonus: du kannst die Kommunikation mit jedem 
x-beliebigen Terminal mitlesen.

: Bearbeitet durch Moderator
von Isi S. (ischmtt)


Lesenswert?

Lothar M. schrieb:
> Mein Tipp: nimm ASCII-Zeichenketten

Geht leider nicht. Die Adressen sind schon so vorgegeben, die kann ich 
nicht ändern.

von Peter D. (peda)


Lesenswert?

Isi S. schrieb:
> Die Adressen sind schon so vorgegeben, die kann ich
> nicht ändern.

Dann soll derjenige das lösen, der sich dieses krude Format ausgedacht 
hat.
Ein Datenformat muß so definiert sein, daß sich Daten und 
Steuerinformationen eindeutig zuordnen lassen. Ansonsten hat der 
Entwickler gepennt oder er ist unfähig.

Beitrag #7509693 wurde vom Autor gelöscht.
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Isi S. schrieb:
> Geht leider nicht. Die Adressen sind schon so vorgegeben, die kann ich
> nicht ändern.
Wie sichert der, der dieses Format vorgegeben hat, die Übertragung ab, 
wenn in den Daten selber kein eindeutiges Ende erkennbar ist?

Was passiert im EMV-Labor? Oder wenn ich da mal mit meinem "Bursttest 
für Anfänger"(**) aka. Viehtreiber draufhalte und ein fehlerhaftes 
Start- oder Datenbit erzeugt wird?


(**) siehe dort im 
Beitrag "Re: Tiefentladungsschutz mit Attiny und P-Kanal Fet"

Das ist ein nettes entwicklungsbegleitendes Tool... ;-)

: Bearbeitet durch Moderator
von Gerald K. (geku)


Lesenswert?

Isi S. schrieb:
> D3 88 00 FF FF 01 00

Werden diese Werte gelesen, dann liegt kein Hex-Format vor. Zahlen im 
Hexformat werden immer als lesbare ASCII-Zeichen (0=0x30, 1=0x31, 2=0x32 
...) übertragen.

Die Daten liegen im **Binär-Format** vor!

Zeichenweise lesen:
1
#include <stdio.h>
2
3
int main() {
4
    char c;
5
6
    printf("Bitte geben Sie ein Zeichen ein: ");
7
8
    // Verwende getchar, um ein Zeichen einzulesen
9
    c = getchar();
10
11
    printf("Sie haben das Zeichen '%c' eingegeben.\n", c);
12
13
    return 0;
14
}

Oder Blockweise:

#include <stdio.h>
1
int main() {
2
    FILE *file;
3
    char buffer[100]; // Ein Puffer, um Daten zu speichern
4
5
    // Datei im binären Modus öffnen
6
    file = fopen("dateiname.txt", "rb");
7
8
    if (file == NULL) {
9
        perror("Fehler beim Öffnen der Datei");
10
        return 1;
11
    }
12
13
    // 10 Zeichen aus der Datei lesen
14
    size_t elements_read = fread(buffer, sizeof(char), 10, file);
15
16
    if (elements_read != 10) {
17
        if (feof(file)) {
18
            printf("Ende der Datei erreicht.\n");
19
        } else {
20
            printf("Fehler beim Lesen der Datei.\n");
21
        }
22
    } else {
23
        printf("Gelesene Daten: %s\n", buffer);
24
    }
25
26
    // Datei schließen
27
    fclose(file);
28
29
    return 0;
30
}

von Martin B. (martin_b563)


Lesenswert?

ähhhm, das Lesen mit fgets dürfte funktioniert haben. Stop Character ist 
„end of line“ und nicht Null. Und bei EOF stoppt fgets ebenfalls.

Die Ausgabe als String funktioniert natürlich nicht. Also einfach mal 
mit der schon vorgeschlagenen for-Schleife probieren. Als Ausgabeformat 
würde ich %.2hhx nehmen.

von Martin B. (martin_b563)


Lesenswert?

Zugegeben: das war für’s Einlesen jetzt nicht hilfreich, denn er erste 
Wert, in dem ein Bytewert 0x0a vorkommt, wird nicht vollständig gelesen.

von Harald K. (kirnbichler)


Lesenswert?

Isi S. schrieb:
>     char adresse[8];
>     fgets(adresse, 8, stdin);

Entdecke den Fehler.

von Gerald K. (geku)


Lesenswert?

Martin B. schrieb:
> Als Ausgabeformat würde ich %.2hhx nehmen.

Ich würde %02x verwenden.

von Gerald K. (geku)


Lesenswert?

Harald K. schrieb:
> Isi S. schrieb:
>> char adresse[8];
>>
>> fgets(adresse, 8, stdin);
>
> Entdecke den Fehler.

Es fehlt der Speicherplatz für den 0-char (Stringende), also char 
adresse[9]

von Gerald K. (geku)


Lesenswert?

Als Funktion würde ich fread() verwenden. Siehe Beispiel.
fgets() ist ungeignet weil es für c-Strings ausgelegt ist.
Bei binären Daten ist fread() besser geeignet.

: Bearbeitet durch User
von Sebastian W. (wangnick)


Lesenswert?

Isi S. schrieb:
> Gibt es eine Möglichkeit die komplette Adresse einzulesen?

Wie ist die Adresse formatiert? Gib mal drei Bespiele. Die zwei Ziffern 
00 sollten das Lesen nicht stoppen ...

LG, Sebastian

von Gerald K. (geku)


Lesenswert?

Sebastian W. schrieb:
> Isi S. schrieb:
>> Gibt es eine Möglichkeit die komplette Adresse einzulesen?
>
> Wie ist die Adresse formatiert? Gib mal drei Bespiele. Die zwei Ziffern
> 00 sollten das Lesen nicht stoppen ...
> LG, Sebastian

Wenn man die Daten, dazu zählt auch die Adresse, mit String-Funktionen 
liest, dann wird es nicht gelingen Adressen in **allen** 
Kombinationsmöglichkeiten zu empfangen. Die Stringfunktionen erlauben 
keinen transparenten Empfang aller Bytekombinationen.

Üblicherweise verwendet man für ein transparentes Lesen die Funktion 
fread().

Die Variable **buffer** kann die Struktur sein, welche die Daten in 
ihrer Reihenfolge im Telegramm abbildet.

Z.B.
1
struct TELEGR {
2
unsigned long adresse;
3
ínt datum1
4
ínt datum2
5
}buffer;

size_t elements_read = fread(buffer, sizeof(TELEGR), 1, file);

Wichtig ist zu beachten ist, dass die Order (MSB ...LSB), abhängig vom 
μP, passt

von Obelix X. (obelix)


Lesenswert?

Isi S. schrieb:
> Einlesen einer Hex Zahl von stdin

Was sind HEX-Zahlen?
Bekommst du jetzt einen Zeichenkette (String, ASCII Zeichen) oder Bytes 
gesendet? Bei einer Zeichenkette ist das 8. Zeichen schon bei der ersten 
00.

D3 88 00 FF FF 01 00
12345678901234567890

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Übrigens ist auch das Betriebssystem hier wichtig, denn stdin arbeitet 
defaultmäßig im Textmodus. Falls das Betriebssystem z.B. Windows sein 
sollte, führt der Stream in diesem Modus beim Lesen auch schon 
Änderungen durch, noch bevor die Daten im Programm ankommen. Dann muss 
man stdin erst mit freopen() auf den Binary-Modus umschalten.

Isi S. schrieb:
> fflush(stdin);

Das hat nach C-Standard undefiniertes Verhalten.

Lothar M. schrieb:
> Wie sichert der, der dieses Format vorgegeben hat, die Übertragung ab,
> wenn in den Daten selber kein eindeutiges Ende erkennbar ist?

Ich würde jetzt bei so einem Format erwarten, dass Adressen keine 
beliebige Länge haben, sondern immer gleich lang sind und sich daraus 
ziemlich eindeutig das Ende ergibt.

von Gerald K. (geku)


Lesenswert?

Obelix X. schrieb:
> Was sind HEX-Zahlen?

Hexzahlen sind ASCII codierte Binärwerte.
Wobei Hexzahlen ASCII '0' bx0000 bis '9' bx1001 und 'A' bx1010 bis 'F' 
bx1111

Ein Byte besteht aus zwei Hexzahlen
Ein Word besteht aus vier Hexzahlen
Ein DWord besteht aus acht Hexzahlen

Hexzahlen können wiederum Binär dargestellt werden:

                 1. 8 Bit Binärwert 2. 8 Bit Binärwert
z.B. "30" Hex => bx0011_0000        bx0011_0000
z.B. "A5" Hex => bx0100_0001        bx0011_0101

Nicht zu vergessen der Hex-String wird mit bx0000_0000 abgeschlossen!

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

Gerald K. schrieb:
> Obelix X. schrieb:
>> Was sind HEX-Zahlen?
>
> Hexzahlen sind ASCII codierte Binärwerte.

Das ist deine Definition von Hexzahlen :)

Für die Hexadezimaldarstellung einer Zahl ist lediglich festgelegt, dass
ein ein Stellenwertsystem verwendet wird, in dem jede Stelle einen Wert
von 0 bis 15 hat, wobei die Werte 10 bis 15 in der für Menschen lesbaren
Schreibweise üblicherweise mit den Buchstaben A bis F notiert werden.

Für die Art und Weise, wie in der Computertechnik die einzelnen Ziffern
jeweils in Gruppen von mehreren Bits codiert werden, gibt es viele
Möglichkeiten und IMHO keine Norm, die einer dieser Möglichkeiten den
Vorzug gibt. Die Codierung jeder Ziffer als ASCII-Symbol ist nur eine
davon.

Im Fall des TE (der sich ja nicht mehr meldet) sind die Hexziffern
vermutlich als gepackte 4-Bit-Gruppen (Nibbles) codiert, was äquivalent
ist mit einer Binärdarstellung, die die Binärziffern als gepackte
1-Bit-Gruppen codiert und der üblichen internen Darstellung von
Integer-Zahlen im Hauptspeicher von Computern entspricht.

von Rolf M. (rmagnus)


Lesenswert?

Yalu X. schrieb:
> Im Fall des TE (der sich ja nicht mehr meldet) sind die Hexziffern
> vermutlich als gepackte 4-Bit-Gruppen (Nibbles) codiert, was äquivalent
> ist mit einer Binärdarstellung,

Das ist dann aber nicht "hex", sondern eben binär.

> die die Binärziffern als gepackte 1-Bit-Gruppen codiert und der üblichen
> internen Darstellung von Integer-Zahlen im Hauptspeicher von Computern
> entspricht.

Du meinst das Dualsystem, bzw. für vorzeichenbehaftete Werte dessen 
Zweierkomplement.

von Steve van de Grens (roehrmond)


Lesenswert?

Rolf M. schrieb:
> Das ist dann aber nicht "hex", sondern eben binär.

Ja, davon gehe ich aus. Sonst wäre das nicht passiert:

Isi S. schrieb:
> Die Adresse wird nur bis zu 88 eingelesen,
> schätzungsweise da die erste 00 (danach) als Ende angesehen wird.

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

Rolf M. schrieb:
> Yalu X. schrieb:
>> Im Fall des TE (der sich ja nicht mehr meldet) sind die Hexziffern
>> vermutlich als gepackte 4-Bit-Gruppen (Nibbles) codiert, was äquivalent
>> ist mit einer Binärdarstellung,
>
> Das ist dann aber nicht "hex", sondern eben binär.

Das kann als etwas ähnliches wie packed BCD angesehen werden, nur eben
für Hexadezimal- statt Dezimalziffern. Man könnte es deswegen auch
"packed BCH" (Binary Coded Hexadecimal) nennen. Da im Gegensatz zu BCD
der Wertebereich der einzelnen Nibbles voll ausgenutzt wird, ist es
letztendlich dasselbe wie binär codiertes Vierersystem und die übliche
Binärdarstellung, nur die Betrachtungsweise ist eine andere.

von Sebastian W. (wangnick)


Lesenswert?

Ich werfe noch mal hämisch Unicode in die erlauchte Runde ...

LG, Sebastian

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.