Avatar billede tagryggen Nybegynder
15. marts 2003 - 22:51 Der er 20 kommentarer og
1 løsning

opsamling / opdeling af datastreng

Jeg har et lille problem...

Jeg er igang med at projekt hvor jeg skal modtage en datastreng fra en cykelcomputer.

Denne datastreng indeholder forskellige værdier og ser i grove træk ud på følgende måde:

talværdi_A*talværdi_B*talværdi_C*talværdi_D# - hvor A,B,C og D er henholdsvis puls, hastighed, km/t og distance.

Mit problem er hvordan min kode skal se ud, sådan jeg kan opsamle og adskille de forskellige talværdier og senere hente og udlæse dem individuelt.

Der bliver dendt en ny datastreng hvert sekund.
Avatar billede hsloth Novice
16. marts 2003 - 10:16 #1
Lad os antage at tallene er integers, en mulighed er at bruge scanf :

int a, b, c, d;
int antalMatched;

antalMatched = sscanf( modtagetTekst, "%d * %d * %d * %d ", &a, &b, &c, &d )
if( antalMatched != 4 )
{
  // Det gik ikke godt - fejlbehandling
}
else
{
  // Vi fik fundet alle fire værdier
}
Avatar billede tagryggen Nybegynder
16. marts 2003 - 11:42 #2
Jeg kan ikke helt se, hvordan denne metode deler datastrengen op i de 4 forskellige værdier den indeholder, og gemmer dem individuelt...?

Du tjekker vel egentlig bare om datastrengen er sendt korrekt...
Avatar billede arne_v Ekspert
16. marts 2003 - 16:21 #3
Nej.

Variablene a, b, c og d får også værdierne.
Avatar billede hsloth Novice
16. marts 2003 - 17:20 #4
Scanf returnerer antallet af variable der har fået tildelt en værdi under scanningen - derfor checker jeg i koden om returværdien er netop 4 - hvis den er det har de fire variable a, b, c og d fået de ønskede værdier.

Check evt. dokumentationen af sscanf:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt_scanf.2c_.wscanf.asp
Avatar billede muffet Nybegynder
16. marts 2003 - 19:21 #5
komplet løsning bare nogle lidt andre ting der bliver overført:

void CBike_A::Decode (char *string, CData *obj) const
{
    char Time_char[5], Cadence_char[4], Puls_char[4], Gear_char[2];
    int Time, Cadence, Puls, Gear;

    strncpy (Time_char, string, 4);
    Time_char[4] = '\0';
    obj->Time = atoi(Time_char);

    strncpy (Cadence_char, string+4, 3);
    Cadence_char[3] = '\0';
    obj->Cadence = atoi(Cadence_char);

    strncpy (Puls_char, string+7, 3);
    Puls_char[3] = '\0';
    obj->Puls = atoi(Puls_char);

    strncpy (Gear_char, string+10, 1);
    Gear_char[1] = '\0';
    obj->Gear = atoi(Gear_char);
}
Avatar billede muffet Nybegynder
16. marts 2003 - 19:22 #6
atoi-funktionen er den der konverterer hele arrayet til integers...
Avatar billede arne_v Ekspert
16. marts 2003 - 19:47 #7
muffet>

hsloths løsning kan håndtere vilkårlige felt-bredder.

Din løsning håndterer kun feltbredder 4+3+3+1.
Avatar billede muffet Nybegynder
16. marts 2003 - 19:53 #8
arne_v->
jeg ved det virker til det projekt han laver, for jeg laver præcis det samme i øjeblikket. Det er et fast antal int der bliver sendt i den streng fra cykelcomputeren, så det virker fint nok...
Men du må da gerne vise en løsning der kan håndtere vilkårligt antal felter, for det kan både tagryggen og jeg bruge! :)
Avatar billede olennert Nybegynder
16. marts 2003 - 20:11 #9
For at håndtere et vilkårligt antal felter, så kig på strtok eller strchr.

Muffet, som Arne skriver, så er hsloths løsning mere generel (og derfor IMO bedre). Men hvis du insisterer på at lave det med strncpy, så brug i det mindste nogle konstanter i stedet for hårdkodede værdier.
Avatar billede arne_v Ekspert
16. marts 2003 - 20:11 #10
Fast antal jo, men også fast feltbredde ?

Vil gear altid være i intervallet 0-9 ?  (jeg har hørt om cykler
med mere end 9 gear)
Avatar billede muffet Nybegynder
16. marts 2003 - 20:16 #11
olennert - >
nårh ja... men jeg har kun været i gang lidt længere end et halvt år... men jeg tager kritikken til mig, og det ender jo nok også med at jeg retter min egen kode :)

arne_v - >
ja, gearet er i intervallet 0-9, det er en kondicykel, ikke en alm. cykel med udvendige gear, for der har min i hvert fald 27, så det er jeg da godt klar over :)
Avatar billede arne_v Ekspert
16. marts 2003 - 20:16 #12
Variabelt antal felter kan håndteres på flere måder.

Den simpleste er hvis første felt angiver antal efterfølgende felter som i:
2 1 2
3 11 22 33
0
1 1111

Så læser man bare det første felt og laver en for løkke som looper det antal gange.

Hvis man ikke har det men linie-skift har betydning, så må man man
parse en linie ad gange og se hvormange tal der er.
Avatar billede segmose Nybegynder
17. marts 2003 - 11:10 #13
Så kan i jo lige tænke lidt over hvorfor det her program (frit efter hslot)
giver "forkerte" retur væredier.
Simple løsning: Afgrænds løsninger til kun at tage forbehold for at tallene
kun må være mindre end den mindst tilladte MAX_INT.
Lidt mere kompliceret brug strtol og enten strtok eller mere som
muffet's løsning, men da i bruger C  skulle i nok kikke på noget med << istedet.

#include <stdlib.h>
#include <stdio.h>

void Beregn(char const *modtagetTekst) {
  int
    a, b, c, d;
  int
    antalMatched;

  antalMatched = sscanf( modtagetTekst, "%d * %d * %d * %d ", &a, &b, &c, &d );

  if( antalMatched != 4 ) {
    // Det gik ikke godt - fejlbehandling
    printf("ups - '%s' gik ikke godt\n", modtagetTekst);
  } else {
    // Vi fik fundet alle fire værdier
    printf("ok - '%s' gav %d %d %d %d\n", modtagetTekst,  a, b, c ,d);
  }
}

int main() {
  Beregn("12345678901*1*12*123");
  Beregn("66000*1*12*123");
  Beregn("1*23*456*7890");

  return EXIT_SUCCESS;
}


Y:\TEST>sscanf
ok - '12345678901*1*12*123#' gav -1 1 12 123
ok - '66000*1*12*123#' gav 464 1 12 123
ok - '1*23*456*7890#' gav 1 23 456 7890
Avatar billede olennert Nybegynder
17. marts 2003 - 13:47 #14
segmose ->

Du kan godt lave sscanf-løsningen ligeså robust som strtol-løsningen. Hvis du #include <inttypes.h> så defineres scanf-flag som SCNu64, og typer som uint64_t. Forudsat oversætteren altså har en 64-bit heltalstype. I øvrigt vil der så også gælde at hvis oversætteren *ikke* har en 64-bit heltalstype, så får du det samme problem med strtol, idet long så vil være 32-bit.
Avatar billede segmose Nybegynder
17. marts 2003 - 14:36 #15
Fordelen ved strtol er at du kan få en fejlmelding, at den er i errno er
selvfølgelig stadig et problem.

Den første giver fejl fordi 12345678901 ikke kan være i en long på min compiler, dette ville bliver fanget da errno ville blive sat til ERANGE.

Den anden giver fejl fordi jeg har oversat den på en 16-bit maskine og 66000 ikke kan være i en 16-bit int, dette burde give en fejl da den konverteres til int (66000-65536=464), nu husker jeg ikke lige hvad der bliver kaldt i C  , men i C mener jeg at sscanf med et '%d' kalder atoi som virkelig er (int)strtol(s, (char **)NULL, 10).
Avatar billede olennert Nybegynder
17. marts 2003 - 15:38 #16
segmose -> Du har fuldstændig ret. Men med 64-bit heltal uden fortegn er maksimumværdien 18,446,744,073,709,551,615 hvilket er et forholdsvist stort tal. Hvis dine inddata er garanteret at holde sig mellem 0 og 2^64 - 1, så kan du bruge sscanf med SCNu64 og uint64_t. Hvis ikke, så kan du bruge strtoul, og checke mod ERANGE (og i øvrigt håbe på at en long er 64 bit på den platform).

Fordelen ved uint64_t er at det sædvanligvis er en flytbar indpakning af eksempelvis long long, eller andre oversætterafhængige tingester.

Så med uint64_t og SCNu64 kan du indlæse store tal uden range check, med long kan du måske kun læse 32-bit tal, men med range check. YMMV.
Avatar billede segmose Nybegynder
17. marts 2003 - 15:55 #17
> YMMV

er meget rigtigt.

Jeg ville dog lige bruge 5 sek. på at tænke over data range, det er dog formodentlig ikke et problem her.
Avatar billede tagryggen Nybegynder
17. marts 2003 - 17:02 #18
Når man nu betegner sig selv som ny i C++ sproget så kan man hurtigt blive kvalt i jeres avancherede snak.
Avatar billede segmose Nybegynder
17. marts 2003 - 17:38 #19
Forenklet går det ud på at de data typer som man vælger skal kunne indeholde de værdier som i forsøger at indlæse, det nytter ikke at ville læse 66000 ind i en 16 bit int type. (læs i din include/limits.h hvilke værdier der på denne compiler på denne maskine der er tillad for hvilke typer).

Så diskuterer vi den sikreste måde at indlæse på, enten tager man forbehold for at de data man vil indlæse er i den formoede værdi område eller man sikre sig både i den ene ende og den anden.

muffet's er den mest usikre metode, den virker kun hvis data er lige præcis som han formoder, der checkes ikke for fejl værdier og position af adskillelser.

hsloth's er ok hvis værdierne holder sig inden for 'int' området, hvilket sikkert er tilfældet her.

olennert foreslår at man benytter nogen af de nye type der er defineret i nyeste C  standard som forøger værdi området enormt.

Jeg er bare lidt paranoid over ting man modtager fra andre enheder (cyclecomputer->PC)
Er transmission ufejlbarlig? fanger man fejl i transmissionen så hvis der pludselig står "3x7*" istedet for "347*" at det bliver til en fejl, hvad det gør i hsloth's men ikke i muffet's.
Sender alle modeller nøjagtig ens? har felterne fast bredde uanset værdi? hvis en af felterne bliver længere eller korterer alt efter værdien fejler muffet's også.
Avatar billede olennert Nybegynder
17. marts 2003 - 17:52 #20
tagryggen -> Undskyld, det er let at blive revet med. Det er et emne der interesserer mig (og formentlig også interesserer segmose, ellers ville han nok ikke bruge tid på dette her). Og så kan man godt komme til at glemme målgruppen.

Men det er altid en god ide at tænke lidt over hvordan ens inddata ser ud, og hvordan ens kode kommer til at håndtere fejlsituationer. Det er fint nok (i kode der ikke skal køre i rigtig produktion; det virker lidt som om det her handler om en opgave på en eller anden uddannelsesinstitution) at antage at ens inddata altid er perfekte, men så husk lige at dokumentere den antagelse.

Så læs lige segmoses opsummering af diskussionen. Tankerne omkring hvor store heltal egentlig kan blive er ganske interessante. Og det bliver rigtigt spændende når vi kommer over i flydende tal :-).
Avatar billede arne_v Ekspert
17. marts 2003 - 19:09 #21
Men sommetider er det en god ting at bemærke, hvis en feature er knyttet
til en nyere standard.

inttypes.h er fra en X/Open standard og er selvom standarden ikke
er ny ikke med i alle C compilere.

limits.h er med i ANSI C standarden og bør være i alle compilere idag.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester