Forum: Mikrocontroller und Digitale Elektronik C: Int to String Funktion schlägt fehl.


von high-side (Gast)


Lesenswert?

Hallo,

ich habe mir aus dem Artikel:
http://www.mikrocontroller.net/articles/Festkommaarithmetik

Die Funktion: void my_uitoa(uint32_t zahl, char* string)
abgeschaut.

Mein Programm sieht so aus:
1
#include "asuro.h"
2
3
void my_uitoa(unsigned int zahl, unsigned char* char_p, unsigned char start) {
4
  char i;                             // schleifenzähler
5
  
6
  for(i=start; i>=(start-3); i--) {
7
    char_p[i]=(zahl % 10) +'0';         // Modulo rechnen, dann den ASCII-Code von '0' addieren
8
    zahl /= 10;
9
  }
10
}
11
12
int main (void){
13
//                           0   1   2   3
14
 unsigned char char_a[4] = {'1','0','2','3'}; 
15
 unsigned int test_int = 3201;
16
 while (1){
17
     my_uitoa(test_int,char_a,3);
18
     SerWrite(char_a, 4);
19
     // Deklaration von SerWrite(unsigned char* char_p, unsigned char byte_cnt); 
20
 }
21
 return 0;
22
}

Aber leider tut das Programm nicht was es soll! Bzw. es tut gar nix, ich 
habe versucht hinter dem Funktionsaufruf eine LED zu schalten, so weit 
kommt er schon nicht mehr.

Benutze ich SerWrite ohne Aufruf von my_uitoa funktioniert die Ausgabe.. 
also muss der Fehler irgendwo in der Funktion my_uitoa oder im Auruf 
liegen.. aber ich habe gerade Tomaten auf den Augen und finde den Fehler 
nicht..

hab auch schon den Start parameter weggelassen... der soll später (wenns 
mal funktioniert) dazu dienen an verschiedene Stellen in einem string zu 
schreiben..

Achja und den /0 Terminator im String brauche ich auch nicht.. wie 
gesagt funktioniert der Aufruf von SerWrite ohne my_uitoa...

VIELEN DANK!!

von Sven P. (Gast)


Lesenswert?

Ich würde mich mal über Integertypen und Vorzeichen informieren...

von high-side (Gast)


Lesenswert?

kopf kratz

Den Hinweis versteh ich gerade nicht...
Der Schleifenzähler sollte ja auf jeden fall signed sein.. sonst bricht 
die schleife ja nie ab.

Wo habe ich einen signed/unsigned Fehler ???

DANKE !!!

von Johannes M. (johnny-m)


Lesenswert?

Du übergibst der Funktion einen Zeiger (unsigned char* char_p), 
versuchst in der Funktion aber, diesen als Array zu bearbeiten 
(char_p[i]=(zahl % 10) +'0';). Du musst da schon den Zeiger 
dereferenzieren.

Abgesehen davon solltest Du Dir direkt angewöhnen, ASCII-Strings in C 
auch zu terminieren, da Du sonst irgendwann mal Probleme bekommen wirst, 
wenn Du Bibliotheksfunktionen zur Stringverarbeitung bzw. Stringausgabe 
verwenden willst, die alle mit nullterminierten Strings arbeiten.

von Johannes M. (johnny-m)


Lesenswert?

> unsigned char char_a[4] = {'1','0','2','3'};
Das sollte man übrigens auch nicht machen. ASCII-Zeichen (Textzeichen) 
sind in C grundsätzlich vom Typ char und nicht unsigned char. Auch, 
wenn es jetzt nur für Deine eigenen Anwendungsfälle ist, gewöhne es Dir 
aus o.g. Gründen gleich richtig an.

von high-side (Gast)


Lesenswert?

noch mehr am kopf kratz

unsigned char* char_p

ist doch ein Pointer auf (unsigned char) ? Ja, oder net?

und mit char_p[i] wird der Zeiger doch dereferenziert ???
(adresse = &(char_p[0]) + (i * sizeof(unsigned char))  verwirrt bin

Oder habe ich da nen grundsätzlichen Denkfehler drin ???

von Stefan E. (sternst)


Lesenswert?

Johannes M. wrote:
> Du übergibst der Funktion einen Zeiger (unsigned char* char_p),
> versuchst in der Funktion aber, diesen als Array zu bearbeiten
> (char_p[i]=(zahl % 10) +'0';). Du musst da schon den Zeiger
> dereferenzieren.

Er dereferenziert ihn doch mit "[]". Das ist völlig ok so.

von Benedikt K. (benedikt)


Lesenswert?

Johannes M. wrote:
> Du übergibst der Funktion einen Zeiger (unsigned char* char_p),
> versuchst in der Funktion aber, diesen als Array zu bearbeiten
> (char_p[i]=(zahl % 10) +'0';). Du musst da schon den Zeiger
> dereferenzieren.

Nein, muss man nicht. Das funktioniert auch so.


Ich würde anstelle von
 char i;
besser
signed char i;
schreiben, denn char ist nicht immer als signed definiert, das hängt 
etwas von den Compilereinstellungen ab. Und wenn start dann <3 ist, dann 
kann es sein, dass die Schleife ewig läuft.

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


Lesenswert?

>   for(i=start; i>=(start-3); i--) {
Es ist schlecht, den Compiler entscheiden zu lassen, welche Datentypen 
er nehmen darf.
Was kommt das wohl raus?
 ... i>=(start-3) ...   --> ein Vergleich signed mit unsigned

Ich würde den wenigstens Casten, dass der Compiler nicht beliebig 
kreativ sein kann:

   for(i=start; i>=((char)start-3); i--) {


Oder gib deiner Funktion als Parameter einfach mal
     my_uitoa(test_int,char_a, 2 );
Was passiert jetzt?

von Stefan E. (sternst)


Lesenswert?

high-side wrote:

> Wo habe ich einen signed/unsigned Fehler ???

Hier:
1
  char i;                             // schleifenzähler
2
  
3
  for(i=start; i>=(start-3); i--) {

Ob ein char signed oder unsigned ist, liegt im Ermessen des Compilers. 
Bei unsigned kann die Schleife aber ganz schnell zur Endlosschleife 
werden (z.B. bei deinem start=3).
Also:
char i;
->
signed char i;

von high-side (Gast)


Lesenswert?

Du hast schon Recht, dass ich mit Strings anders umgehen sollte... aber 
der Code sollte doch trotzdem funktionieren ???

ich will ja nur bytes übertragen.. wie gesagt erwartet die 
Übertragungsfunktion SerWrite keinen terminierten String sondern einfach 
Bytes... aber soweit kommt er ja leider gar net.... :-(

von Johannes M. (johnny-m)


Lesenswert?

Stefan Ernst wrote:
> Er dereferenziert ihn doch mit "[]". Das ist völlig ok so.
Hast Du Recht. War nicht zu Ende gedacht...

von high-side (Gast)


Lesenswert?

@Stefan:

Hier:
1
  char i;                             // schleifenzähler
2
  
3
  for(i=start; i>=(start-3); i--) {


Du meinst ich muss hier explizit signed angeben ??? ich dachte char wäre 
von natur aus schon ein vorzeichenbehafteter Wert ???

Der Controller ist ein ATMEGA8 ...

von TorstenS (Gast)


Lesenswert?

Hallo,

ich denke, dass das Problem in der Abbruchbedingung liegt. Hier wird 
unsigned char mit signed char verglichen, was im Falle 3 dazu führt, 
dass unsigned char immer größer gleich 0 und damit immer wahr ist.

Gruß
Torsten

von Stefan E. (sternst)


Lesenswert?

high-side wrote:

> Du meinst ich muss hier explizit signed angeben ???

Ja.

> ich dachte char wäre
> von natur aus schon ein vorzeichenbehafteter Wert ???

Nein, nicht notwendigerweise.

von high-side (Gast)


Lesenswert?

@lothar:

ich werde das mit 2 und dem cast mal ausprobieren...

jetzt bin ich aber mal gespannt....

dachte das "char i" hier schon die größte Stolperfalle gewesen wäre ;-) 
... über die ich auch schon gestoplert bin.. dann dachte ich JA das 
wars! Wars aber leider anscheinend doch nicht.... :-(

Danke an alle!


8 Bit können so gemein sein... ;-)

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


Lesenswert?

> 8 Bit können so gemein sein... ;-)
Pass mir ja auf das Bit auf, das ist noch so klein ;-)

> ich werde das mit 2 und dem cast mal ausprobieren...
Wenn du das machst gibt es einen amoklaufenden Pointer (wg. Index = -1).
Nein, du solltest das nur Durchdenken.

von Johannes M. (johnny-m)


Lesenswert?

Kleiner Tip am Rande: Die stdint.h enthält eine ganze Reihe 
easy-to-use-Typdefinitionen (auch 8-Bit-Typen), die eindeutig benannt 
sind und bei denen es folglich keine derartigen Probleme gibt. Bau die 
stdint.h ein und mach es mit int8_t (bzw. im anderen Fall mit uint8_t).

von Karl H. (kbuchegg)


Lesenswert?

Lothar Miller wrote:
>> ich werde das mit 2 und dem cast mal ausprobieren...
> Wenn du das machst gibt es einen amoklaufenden Pointer (wg. Index = -1).
> Nein, du solltest das nur Durchdenken.

Oder was in die gleiche Kerbe schlägt
1
    for(i=start; i>=(start-3); i--) {

Huch, wieso 3? Wo kommen diese 3 her? Was bedeuten sie?
Warum nicht 4 oder 5? Welche Implikationen hat das für die
möglichen Werte in start?

und denk drann:
Wenn in einem Ausdruck sowohl signed als auch unsigned Werte vorkommen, 
wird alles nach unsigned gewandelt!

  i ist bei dir signed
  start ist unsigned

-> Für den Vergleich wird alles nach unsigned gewandelt.

Aber: Als unsigned ausgedrückt, kann i nie den Wert -1 haben!
Der wär aber nötig, wenn start den Wert 3 hat, denn 3 - 3 macht 0
und damit die Schleife abbrechen kann muss i kleiner als 0 werden.
i wird zwar kleiner als 0, aber nicht während des Vergleichs. Während 
des Vergleichs wird i als unsigned Wert angesehen und als unsigned 
gesehen kann i per Definition nicht negativ werden.

von Sven P. (Gast)


Lesenswert?

Ob CHAR mit oder ohne Vorzeichen ist, kann man dem GCC per 
Kommandozeilenargument verklickern.

Besser ist in jedem Fall int8_t, der ist immer mit Vorzeichen.

von Gast (Gast)


Lesenswert?

ISO C89 kennt übrigens auch snprintf(), um Zahlen in Strings 
umzuwandeln:
1
int zahl = 42;
2
char string[123];
3
snprintf(&string, sizeof(string), "%d", zahl);

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.