C: Int to String Funktion schlägt fehl.

Gast #1117471
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!!
Gast
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 !!!
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.
> 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.
Gast
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 ???
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.
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.
Moderator (Firma: Titel) Persönliche Seite
>   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?
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;
Gast
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.... :-(
Gast
@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 ...
Gast
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
Gast
@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... ;-)
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).
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.
Gast
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.
Gast
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);

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 17 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.