www.mikrocontroller.net

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


Autor: high-side (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:

#include "asuro.h"

void my_uitoa(unsigned int zahl, unsigned char* char_p, unsigned char start) {
  char i;                             // schleifenzähler
  
  for(i=start; i>=(start-3); i--) {
    char_p[i]=(zahl % 10) +'0';         // Modulo rechnen, dann den ASCII-Code von '0' addieren
    zahl /= 10;
  }
}

int main (void){
//                           0   1   2   3
 unsigned char char_a[4] = {'1','0','2','3'}; 
 unsigned int test_int = 3201;
 while (1){
     my_uitoa(test_int,char_a,3);
     SerWrite(char_a, 4);
     // Deklaration von SerWrite(unsigned char* char_p, unsigned char byte_cnt); 
 }
 return 0;
}

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!!

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde mich mal über Integertypen und Vorzeichen informieren...

Autor: high-side (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 !!!

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: high-side (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ???

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Benedikt K. (benedikt) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
high-side wrote:

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

Hier:
  char i;                             // schleifenzähler
  
  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;

Autor: high-side (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.... :-(

Autor: Johannes M. (johnny-m)
Datum:

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

Autor: high-side (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Stefan:

Hier:
  char i;                             // schleifenzähler
  
  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 ...

Autor: TorstenS (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: high-side (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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... ;-)

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
    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.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Gast (Gast)
Datum:

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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.