Forum: PC-Programmierung C & gcc & sscanf & longdouble als xx.xxxxxxxxE+yy


von Andreas F. (bazo)


Lesenswert?

Hallo,

ich bekomme von meinem Frequenzzähler via BUS folgenden String:

FA +0010.00001587E+06
Per strtok setze ich einen pointer auf die 1 und versuche dann die Zahl 
mit allen Stellen einzulesen.

->
long double strip_answer(char *answer, char *para) {
  char delimiter[] = " +";
  char *ptr;
  long double value;

  fprintf(stderr,"Answer %s", answer);
        ptr = strtok(answer, delimiter);
  if(! strcmp(ptr,para)) {
          fprintf(stderr,"Abschnitt gefunden: %s\n", ptr);
    ptr = strtok(NULL, delimiter);
    sscanf(ptr,"%LG",&value);
    fprintf(stderr,"Ausgabe %LG\n\r", value);
  }
  return value;
}

->
Answer FA +0010.00001520E+06
Abschnitt gefunden: FA
Ausgabe 10
->

Wo ist mein Denkfehler?

Gruß Andreas

von Stefan E. (sternst)


Lesenswert?

Der zweite strtok-Aufruf ersetzt das + hinter dem E durch '\0'.

von Rolf M. (rmagnus)


Lesenswert?

Andreas F. schrieb:
> Hallo,
>
> ich bekomme von meinem Frequenzzähler via BUS folgenden String:
>
> FA +0010.00001587E+06
> Per strtok setze ich einen pointer auf die 1 und versuche dann die Zahl
> mit allen Stellen einzulesen.

Du setzt ihn nicht auf die 1, sondern auf die erste 0, was aber nichts 
macht.
Das Problem ist, dass du an allen Leerzeichen und allen +-Zeichen eine 
Trennung machst, also bekommt strtok als String übergeben: 
"0010.00001587E", denn nach dem E steht ein +. Also bekommt es als 
Ergebnis 10.00001587 raus, da die Zehnerpotenz fehlt. Warum machst du 
überhaupt das + weg? Das stört doch gar nicht.

von Dirk B. (dirkb2)


Lesenswert?

Ein
1
 sscanf(answer, "FA%Lf", &value);
sollte reichen.
Die Formatspecifier e,f und g sind bei scanf identisch

Sonst gibt es auch noch strtold

Aber warum überhaupt ein long double?
Der Zahlenwert mit der Genauigkeit passt noch in ein double

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Dirk B. schrieb:
> Aber warum überhaupt ein long double?
> Der Zahlenwert mit der Genauigkeit passt noch in ein /double/

Abgesehen davon kann es je nach verwendetem Betriebssystem und Plattform 
sein, dass double und long double sowieso das gleiche sind.

: Bearbeitet durch User
von Andreas F. (bazo)


Lesenswert?

@Rolf & Stefan
Jopp, danke

@Dirk & Rolf
long double zum testen, weil ich mir nicht sicher war, wo mein Fehler 
lag.


sscanf(answer, "FA%Lf", &value);
Jein,
Ja, funktioniert:
Nein. Weil ich die Routine modular halten will und bei den Antworten vom 
Bus schauen muss was im Header steht, (FA/FB/FC für die 3 Eingänge des 
Counters oder Pegel beim SA/Meßsender.

Gruß Andreas

von Dirk B. (dirkb2)


Lesenswert?

Na dann
1
char kanal;
2
sscanf(answer, "F%c%Lf", &kanal, &value);
In kanal steht dann 'A', 'B' oder 'C'.
Und wenn nicht, liegt ein Fehler vor.

Oder
1
char kanal[3];
2
sscanf(answer, "%2s%Lf", kanal, &value);
Dann halt mit "FA", "FB" oder "FC"

Es bleibt bei einem Einzeiler.
Unterschätze nicht die Macht von scanf

von bazo (Gast)


Lesenswert?

Dirk B. schrieb:
> Na dann
>
1
> char kanal;
2
> sscanf(answer, "F%c%Lf", &kanal, &value);
> In kanal steht dann 'A', 'B' oder 'C'.
> Und wenn nicht, liegt ein Fehler vor.
>
> Oder
>
1
> char kanal[3];
2
> sscanf(answer, "%2s%Lf", kanal, &value);
> Dann halt mit "FA", "FB" oder "FC"
>
> Es bleibt bei einem Einzeiler.
> Unterschätze nicht die Macht von scanf

Ja, weil es für den einen Fall funktioniert.

Nein, weil ich das als Standardroutine für alle GPIB read haben will.
Aufbau ist HH +DDDDDDDD.DDDD[cr\LF]

Wobei HH dann z.b 'DU', FA, AT sein kann, je nach Meßgerät und Funktion,

Die Funktion muss ich eh noch erweitern, weil die Antwort beim bei einem 
DDS Arbitrary Funktionsgenerator deutlich komplexer ist.


Gruß Andreas

von Dirk B. (dirkb2)


Lesenswert?

bazo schrieb:
>> char kanal[3];
>> sscanf(answer, "%2s%Lf", kanal, &value);> Dann halt mit "FA", "FB" oder "FC"
>>
>> Es bleibt bei einem Einzeiler.
>> Unterschätze nicht die Macht von scanf
>
> Ja, weil es für den einen Fall funktioniert.
>
> Nein, weil ich das als Standardroutine für alle GPIB read haben will.
> Aufbau ist HH +DDDDDDDD.DDDD[cr\LF]

Passt doch. In kanal steht dann das HH

Man kann den Formatstring auch noch anpassen, wenn es mehr als zwei H 
sind.

: Bearbeitet durch User
von Dirk B. (dirkb2)


Lesenswert?

Das Problem von strtok ist, dass es den String verändert (an die 
Position vom Delimiter wird ein '\0' geschrieben.

Und es ist nicht reentrant/threadsafe.
Wenn in einer der rufenden/parallelen Funktionen noch eine nicht 
abgeschlossenen strtok-Suche offen ist, geht das in die Hose.

von bazo (Gast)


Lesenswert?

Dirk B. schrieb:
> bazo schrieb:
>>> char kanal[3];
>>> sscanf(answer, "%2s%Lf", kanal, &value);> Dann halt mit "FA", "FB" oder "FC"
>>>
>>> Es bleibt bei einem Einzeiler.
>>> Unterschätze nicht die Macht von scanf
>>
>> Ja, weil es für den einen Fall funktioniert.
>>
>> Nein, weil ich das als Standardroutine für alle GPIB read haben will.
>> Aufbau ist HH +DDDDDDDD.DDDD[cr\LF]
>
> Passt doch. In kanal steht dann das HH
>
> Man kann den Formatstring auch noch anpassen, wenn es mehr als zwei H
> sind.

Auch wenn die Anzahl der Parameter und das Trennzeichen sich 
unterscheidet?
Mittels strtok kann ich solange die Antwort durchlaufen, bis ich alle 
Parameter habe.

Dirk B. schrieb:
> Das Problem von strtok ist, dass es den String verändert (an die
> Position vom Delimiter wird ein '\0' geschrieben.
>
> Und es ist nicht reentrant/threadsafe.
> Wenn in einer der rufenden/parallelen Funktionen noch eine nicht
> abgeschlossenen strtok-Suche offen ist, geht das in die Hose.

Das trifft hier nicht zu, es wird über die Funktion aus der libgpip oder 
direkt von /dev/usbtmc die Antwort gelesen und dann die Antwort zerlegt, 
das ganze in einem Programm. Und selbst wenn ich aus dem Auslesen 
jemalss ein eigenen Thread mache, Schnittstelle ist immer record.xyz. 
Der Stringinhalt ist danach eh obsolet.

Überschrieben, weil ich den Wert zyklisch auslese.
Überschrieben, weil ich den nächsten Query absetze.
Oder die Routine wird dann irgendwann durch den User wieder aufgerufen, 
daa wir das eh neu vom Bus eingelesen.

Gruß Andreas
PS:
Gibt es in C eine Funktion, die analog zu int main(int argc, char 
*argv[] funktioniert? Aufrufen mit einem String und in der Funktion 
bekommt man die einzelnen Argumente aufgedröselt geliefert?

von Dirk B. (dirkb2)


Lesenswert?

bazo schrieb:
> PS:
> Gibt es in C eine Funktion, die analog zu int main(int argc, char
> *argv[] funktioniert? Aufrufen mit einem String und in der Funktion
> bekommt man die einzelnen Argumente aufgedröselt geliefert?

Das macht nicht die Funktion sondern das Betriebssystem bzw. der 
Startupcode.

Möchtest du eine variable Anzahl Argumente benutzen?

Man kann das aber mit scanf und einer Schleife hinbekommen.

: Bearbeitet durch User
von bazo (Gast)


Lesenswert?

Dirk B. schrieb:
> bazo schrieb:
>> PS:
>> Gibt es in C eine Funktion, die analog zu int main(int argc, char
>> *argv[] funktioniert? Aufrufen mit einem String und in der Funktion
>> bekommt man die einzelnen Argumente aufgedröselt geliefert?
>
> Das macht nicht die Funktion sondern das Betriebssystem bzw. der
> Startupcode.
>
> Möchtest du eine variable Anzahl Argumente benutzen?
>
> Man kann das aber mit scanf und einer Schleife hinbekommen.

Ja, nur weiss ich nicht, ob ich immer die erwartete Anzahl an Parameter 
zurückbekomme und die Reihenfolge ob String oder numerisch ist völlig 
frei:

vom DDS Arbitrary Funktionsgenerator z.b.
BSWV WVTP, 
SINE,FRQ,100HZ,PERI,0.01S,AMP,2V,OFST,0V,HLEV,1V,LLEV,-1V,PHSE,0
Vom Zähler/den einem SA halt obiges HH DDDD.DDDDE0x
Den zweite SA/Bolometer habe ich noch nicht angeschaut

Als Trennzeichen habe ich je nach dem " ",";",",",:"
Der Grundaufbau ist immer gleich,
- Bedienoberfläche für die wichtigsten Einstellungen

- Capture des aktuellen Bildes
- Kurvenschreiber (Datenlogger)

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.