Hi Leute,
das sind meine ersten Gehversuche auf einem AVR, bislang hab ich "nur"
in Windows programmiert und schon nach kurzer Zeit brauchte ich eine
Funktion die Hexa-Strings wieder in Zahlen umwandelt, also hab ich mir
folgende Funktionen geschrieben und da es sicher noch andere Menschen
mit diesem Problem gibt, hab ich sie hier gleich mal veröffentlicht.
Wenn noch jemand optimierungspotential hat bitte posten.
Könntest du mal näher erläutern, welche Nebenbeigungung
für die Funktion atohex gelten?
So wie ich das sehe
* Der String muss ein Vielfaches von 4 lang sein. Du versuchst
anscheinend immer 2 Bytes zu konvertieren.
Warum eigentlich? Das würde ich von einer allgemeinen
Funktion nicht erwarten. Ein Vielfaches von 2 würde mir
einleuchten, da ja immer 2 char eine Hex-Ziffer bilden.
* Was hat es hiermit auf sich?
uiTmp = cStore[3] | cStore[2] | cStore[1] | cStore[0];
if( uiTmp == 0xFF )
return 0;
Dafür finde ich überhaupt keine einleuchtende Erklärung
* Wäre es nicht vernünftig, wenn die Funktion die Anzahl
der konvertierten Bytes zurückliefern würde?
* Deine Funktion hat einen Kardinalfehler, wie ihn auch die
Funktion gets() hat:
Du übergibst nirgends wie gross den der Buffer ist, in den
die konvertierten Bytes geschrieben werden. So wie sie jetzt
ist, hat die Funktion atohex() keine Chance sich gegen Buffer-
überläufe zur Wehr zu setzen
* Der strlen() da drinnen stösst mir sauer auf.
* Alles in allem denke ich, dass diese Funktion nicht so universell
ist, wie du denkst. Da steckt einiges an Spezialwissen drinnen,
wie der String aufgebaut sein muss, dass du aber nicht beschreibst.
Eins vorweg, ich hatte einen Denkfehler als ich die Funktion schrieb und
zwar dachte ich, was vollig abwegig ist auf einem 8 bit risc Kontroller,
das er den speicher in 16 bit blöcken verwaltet.
1
uint8_tatohex(char*pString,uint8_t*pBuffer)
2
{
3
uint8_tcStore[2];
4
uint8_tuiTmp;
5
uint8_ti;
6
uint8_t*iHexLength=pBuffer;
7
uint8_tiLength=strlen(pString);
8
div_tsDiv=div(iLength,2);
9
10
cStore[0]=0;cStore[1]=0;
11
12
if(sDiv.rem)sDiv.quot++;
13
14
for(i=0;i<sDiv.quot;i++)
15
{
16
if(sDiv.rem)
17
{
18
for(uiTmp=2-sDiv.rem;uiTmp<2;uiTmp++)
19
cStore[uiTmp]=getHexValue(*pString++);
20
sDiv.rem=0;
21
}
22
else
23
{
24
for(uiTmp=0;uiTmp<2;uiTmp++)
25
cStore[uiTmp]=getHexValue(*pString++);
26
}
27
28
uiTmp=cStore[1]|cStore[0];
29
if(uiTmp==0xFF)
30
return(pBuffer-iHexLength);
31
32
*pBuffer=((cStore[0]<<4)&0xF0)|(cStore[1]&0xF);
33
pBuffer++;
34
}
35
36
return(pBuffer-iHexLength);
37
}
Karl heinz Buchegger wrote:
> Könntest du mal näher erläutern, welche Nebenbeigungung> für die Funktion atohex gelten?>> So wie ich das sehe> * Der String muss ein Vielfaches von 4 lang sein. Du versuchst> anscheinend immer 2 Bytes zu konvertieren.> Warum eigentlich? Das würde ich von einer allgemeinen> Funktion nicht erwarten. Ein Vielfaches von 2 würde mir> einleuchten, da ja immer 2 char eine Hex-Ziffer bilden.
1
if(sDiv.rem)
2
{
3
for(uiTmp=4-sDiv.rem;uiTmp<4;uiTmp++)
4
cStore[uiTmp]=getHexValue(*pString++);
5
sDiv.rem=0;
6
}
und jetzt
1
if(sDiv.rem)
2
{
3
for(uiTmp=2-sDiv.rem;uiTmp<2;uiTmp++)
4
cStore[uiTmp]=getHexValue(*pString++);
5
sDiv.rem=0;
6
}
Dieser Code rechnet damit, das die Länge vom String kein Vielfaches von
2 oder 4 ist.
>> * Was hat es hiermit auf sich?> uiTmp = cStore[3] | cStore[2] | cStore[1] | cStore[0];> if( uiTmp == 0xFF )> return 0;> Dafür finde ich überhaupt keine einleuchtende Erklärung
Das ist eine einfache Fehlerkontrolle, wenn die Funktion "getHexValue"
nur bei einem Wert einen Fehler erkennt bricht die Funktion ab, da der
Rückgabewert der Funktion "getHexValue" bei einem Fehler 0xFF ist, was
bei einem richtigen Wert nie der Fall sein kann. Ist also das logische
ODER dieser Werte gleich 0xFF ist ein Fehler aufgetreten.
>> * Wäre es nicht vernünftig, wenn die Funktion die Anzahl> der konvertierten Bytes zurückliefern würde?
das war der Grund wieso ich überhaupt einen Rückgabewert mit integriert
hatte, nur hab ich diese Funktionalität dann wohl irgendwie aus den
Augen verlohren. :P
>> * Deine Funktion hat einen Kardinalfehler, wie ihn auch die> Funktion gets() hat:> Du übergibst nirgends wie gross den der Buffer ist, in den> die konvertierten Bytes geschrieben werden. So wie sie jetzt> ist, hat die Funktion atohex() keine Chance sich gegen Buffer-> überläufe zur Wehr zu setzen
Wenn man ordentlich programmiert muss man solch unnötige Kontrollen
nicht durchführen.
>> * Der strlen() da drinnen stösst mir sauer auf.
ob ich nun strlen oder while(*String++) iLen++; mache ist ja egal,
letztentlich brauch ich die länge des Strings.
>> * Alles in allem denke ich, dass diese Funktion nicht so universell> ist, wie du denkst. Da steckt einiges an Spezialwissen drinnen,> wie der String aufgebaut sein muss, dass du aber nicht beschreibst.
der String wird einfach in dem Format "fE0fAc98F" übergeben, wobei die
Länge egal ist.
Tim
>>>> * Deine Funktion hat einen Kardinalfehler, wie ihn auch die>> Funktion gets() hat:>> Du übergibst nirgends wie gross den der Buffer ist, in den>> die konvertierten Bytes geschrieben werden. So wie sie jetzt>> ist, hat die Funktion atohex() keine Chance sich gegen Buffer->> überläufe zur Wehr zu setzen>> Wenn man ordentlich programmiert muss man solch unnötige Kontrollen> nicht durchführen.
Na dann viel Spass im wirklichen Leben :-)
Die Anzahl von Programmabstürzen, Hackerangriffe und sonstigen
Ungereimtheiten die auf das Konto von gets() wegen fehlender
Prüfmöglichkeiten gehen sind Legende.
Du wärst der allererste Programmierer dem ein so läppischer
Fehler wie falsche Buffergrösse noch nie passiert ist.
Gratulation. Oder besser: Warte mal ein Weilchen, das kommt
schon noch.
>> * Der strlen() da drinnen stösst mir sauer auf.>> ob ich nun strlen oder while(*String++) iLen++; mache ist ja egal,> letztentlich brauch ich die länge des Strings.
Was ich meine und andeuten wollte: Wozu musst du überhaut
die Länge im Vorfeld kennen. Geh durch den String durch bis
du auf ein '\0' stösst oder ein Zeichen, das nicht
konvertiert werden kann und gut ists. So wies jetzt ist,
durchläufst du den String 2-mal: Einmal um die Länge
festzustellen und einmal um die Konvertierung zu machen.
Nur so als Skizze ohne Fehlerhandling
uint8_t atohex( char* pString, uint8_t* pBuffer )
{
uint8_t* pTmp = pBuffer;
while( *pString ) {
*pBuffer = getHexValue( *pString++ ) << 4;
if( *pString == '\0' )
return pBuffer - pTemp;
*pBuffer++ |= getHexValue( *pString++ );
}
return pBuffer - pTemp;
}
Das könnte doch die Grundstruktur sein. Dazu brauch ich keine
Länge im Vorfeld wissen.
> Was ich meine und andeuten wollte: Wozu musst du überhaut> die Länge im Vorfeld kennen. Geh durch den String durch bis> du auf ein '\0' stösst oder ein Zeichen, das nicht> konvertiert werden kann und gut ists. So wies jetzt ist,> durchläufst du den String 2-mal: Einmal um die Länge> festzustellen und einmal um die Konvertierung zu machen.>> Nur so als Skizze ohne Fehlerhandling>> uint8_t atohex( char* pString, uint8_t* pBuffer )> {> uint8_t pTmp = pBuffer;>> while( *pString ) {> *pBuffer = getHexValue( *pString++ ) << 4;> if( *pString == '\0' )> return pBuffer - pTemp;> *pBuffer++ |= getHexValue( *pString++ );> }>> return pBuffer - pTemp;> }>> Das könnte doch die Grundstruktur sein. Dazu brauch ich keine> Länge im Vorfeld wissen.
an sich ja, nur hast du dann dein eigenes Szenario außer Acht gelassen
und zwar, wenn der String kein Vielfaches von 2 ist, aber du hast recht,
da ist Verbesserungspotential, ich kann die div weglassen und auf das
bit 0 testen. Denn ich geh davon aus, das wenn der String kein
Vielfaches von 2 ist, das die erste HexZahl nicht komplett übergeben
wurde. In etwa so "Fa3" da man ja meist dann die führende 0 weglässt.
Tim
> wenn der String kein Vielfaches von 2 ist
Genau das habe ich berücksichtigt.
Darum kümmert sich der if in der Schleife.
Zumindest passiert nichts. Ich nehme dann halt an,
dass noch eine 0 kommen muesste. Ist nur eine Annahme (*)
und sollte eigentlich nicht auftreten.
> In etwa so "Fa3" da man ja meist dann die führende 0 weglässt.
Ist auch so eine Annahme (*). Allerdings komplizierter zu
berücksichtigen. IN so einem Fall kommt man um den strlen()
nicht mehr rum. Wenn ich aber die Daten per Übertragung von
einem anderen µC kriege, dann schreibe ich dem vor, dass
er führende Nullen auch mit angeben muss. Für das
gewöhnliche Fussvolk, dass den Hex-String per Tastatur
eingibt mach ich eine 2-te Funktion, die per strlen checkt
ob die Anzahl stimmen kann. Wenn nicht hänge ich eine "0"
davor und rufe atohex() auf.
Das einzige was ich unberücksichtigt lies ist, wenn
sich ein falsches Zeichen im String befindet.
Aber ich sagte ja: Fehlerbehandlung mal aussen vor.
Das zu integrieren + überprüfen ob der Ausgabebuffer
nicht überlaufen wird, ist trivial.
(*)letztendlich hängt es davon ab, wer am anderen Ende
der Leitung sitzt, welche Annahme ich treffe. Wichtig
ist nur, dass in der Funktion nicht Verbotenes passiert.