mikrocontroller.net

Forum: Compiler & IDEs Integer-Wert in ASCII-char


Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich möchte einen Integer-Wert in einen char umwandeln, damit ich den 
Wert über UART verschicken kann.


Wie löse ich das am geschicktesten, wenn ich auch mal mehr als eine 
Ziffer umwandeln will? Die Funktion "itoa" ist leider anscheinend bei 
meinem uC nicht implementiert.

Danke.

TechInfo

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Die Funktion "itoa" ist leider anscheinend bei meinem uC nicht
> implementiert.
Und welcher ist "Dein" µC? Um die Funktion nutzen zu können, musst Du 
schon die stdlib.h einbinden. Und das sollte bei allen µCs mit 
ausreichend Speicherressourcen funktionieren (wobei itoa gar nicht so 
viel Speicher benötigt)

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Den Xilinx Microblaze auf einem SpartanIIE.

In der mitgelieferten stdlib ist die Funktion nicht definiert (atoi 
dagegn schon).

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gibt es keine andere Möglichkeit? Wie ist denn die Funktion itoa 
implementiert?

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schau mal da:
Beitrag "Integer-Zahl in String mit bestimmter Zeichenlänge"
Da ist grad eben eine Methode beschrieben, wie es ohne 
Bibliotheksfunktionen geht.

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da ging es aber doch darum, dass er führende Nullen haben wollte wenn 
die Zahl kleiner ist als der String. Oder?

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das geht aber auch ohne führende Nullen. Die Umwandlung ist im Prinzip 
die selbe...

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thx, hab's schon ausprobiert. Jetzt warte ich noch auf die Erklärung ;)

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

Bewertung
0 lesenswert
nicht lesenswert
TechInfo wrote:
> Thx, hab's schon ausprobiert. Jetzt warte ich noch auf die Erklärung ;)

Und auch die steht schon dort.
Aber du solltest wirklich versuchen solch einfache Funktionen
ohne fremde Hilfe zu verstehen: Papier und Belistift nehmen
und selbst mal Computer spielen. Das hilft ungemein.

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Karl-Heinz Buchegger

Danke. Nachdem ich kurz nachgeschlagen habe wie die modulo-Division
funktioniert war das Nachvollziehen kein Problem. Trotzdem, von selbst
auf so etwas zu kommen ist wieder eine andere Geschichte...

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Morgen,

gibt es denn auch eine ähnliche Möglichkeit für float-Variablen?

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

Bewertung
0 lesenswert
nicht lesenswert
TechInfo wrote:
> Morgen,
>
> gibt es denn auch eine ähnliche Möglichkeit für float-Variablen?

Sicher. Geht fast völlig analog.

Den Vorkommaanteil kannst du ja schon bearbeiten
(Fortgesetzte Division durch 10 und mittels Restbildung
bei der Division durch 10 die Einerstelle extrahieren).

Der Nachkommaanteil ist sogar noch einfacher:

Wenn du 0.89654
mit 10 multiplizierst, erhältst du: 8.9654
Davon schneidest du (zb durch zuweisen zu einem int) den
Nachkommanteil ab und erhältst 8 -> ausgeben
Von den 8.9654 ziehst du die 8 ab und kriegst 0.9654
und jetzt wiederholt sich das Spielchen solange bis du
genügend Kommastellen ausgegeben hast:

  0.9654 * 10 ->  9.654       -> 9
                 -9
                  -----
                  0.654

  0.654 * 10 ->  6.54         -> 6
                -6
                 ----
                 0.54

  0.54 * 10 ->   5.4          -> 5
                -5
                ----
                 0.4

  0.4 * 10       4.0          -> 4
                -4
                ----
                 0.0



Das Grundprinzip ist also immer mittels Multiplikation
bzw. Division mit 10 oder auch Restbildung, sich die gewünschten
Informationen so zurecht zu legen, dass man sie leicht
weiterverarbeiten kann. Und jetzt rate mal warum unser gewohntes
Zahlensystem das 10-er System heist :-)

Du musst dir nur klar machen, dass eine Zahl 568
auch geschrieben werden kann als  5 * 100 + 6 * 10 + 8
oder aber, was gleichbedeutend ist: 5 * 10^2 + 6 * 10^1 + 8 * 10^0

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hey, klasse. Vielen Dank.

Mein Problem ist jetzt noch, dass ich keine führenden Nullen haben 
möchte, deshalb muss ich die Anzahl der Ziffern der Int-Zahl genau 
kennen, um die dann als Schleifenindex verwenden zu können.

Da müßte doch auch etwas ähnliches machen können, oder? Für int-Zahlen 
könnte man ja solange dividieren lassen, bis null heraus kommt. Dann 
müßte man den Schleifenkopf eben leicht ändern. Aber für float?

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Für int hab ich mir jetzt so geholfen:
     j=z;
  while (j>0)
  {
    j=j/10;
    i++;
  }
  
  while(--i >= 0)
  {
    s1[i] = '0' + z % 10;
    z /= 10;
  }  

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

Bewertung
0 lesenswert
nicht lesenswert
TechInfo wrote:
> Für int hab ich mir jetzt so geholfen:
>
>
     j=z;
>   while (j>0)
>   {
>     j=j/10;
>     i++;
>   }
> 
>   while(--i >= 0)
>   {
>     s1[i] = '0' + z % 10;
>     z /= 10;
>   }
> 

So kann man das machen, muss es aber nicht. Divisionen
sind teuer!
Dein Problem ist doch, dass in der Standardschleife ...
  i = 0;
  while( z > 0 ) {
    s1[i++] = '0' + z % 10;
    z /= 10;
  }
  s1[i] = '\0';

... die Stellen genau falsch herum herauspurzeln. Das heist
der String in s1 ist genau falsch herum.
Das kann aber leicht behoben werden:
Etweder indem du den String zunächst in einem Zwischenspeicher
generieren lässt, oder aber indem der String im Nachhinein
gespiegelt werden muss.

Zwischenspeicher:
Das ist sicherlich die einfachste Variante und braucht ein
bischen zusätzlichen Speicher:
void foo( int z, char* Buffer )
{
  char s1[7];   // 10 Stellen reichen für einen int leicht
                // aus. Der Wertebereich ist ja -32768 bis +32767
  int j;
  int i = 0;

  while( z > 0 ) {
    s1[i++] = '0' + z % 10;
    z /= 10;
  }

  // jetzt da wir wissen wieviele Stellen tatsächlich benötigt
  // werden (nämlich i) können die Zeichen in den Zielstring
  // an die richtige Stelle umkopiert werden:

  for( j = 0; j < i; ++j )
    Buffer[i-j-1] = s1[j];

  Buffer[i] = '\0';
}

Da muss jetzt natürlich noch eine Behandlung für negative Zahlen
rein und auch die 0 muss getrennt behandelt werden. Das ist aber
als Übungsaufgabe für den Leser weitergegeben.

Die andere Möglichkeit ist es den String, der ja verkehrt herum
generiert wurde, zu spiegeln.
Dazu betrachten wir einfach mal einen String von dem wir
die Länge kennen (und das tun wir, die Divisionschleife
hinterlässt diese ja in i)

  +---+---+---+---+---+---+---+---+
  | a | b | c | d | e | f | g | h |
  +---+---+---+---+---+---+---+---+

um diesen String (ohne zusätzliches Array) zu spiegeln, genügt
es jeweils das erste mit dem letzten Element zu vertauschen,
dann das zweite mit dem vorletzten usw. bis man in der Mitte
angekommen ist.

  +---+---+---+---+---+---+---+---+
  | a | b | c | d | e | f | g | h |
  +---+---+---+---+---+---+---+---+
    ^                           ^
    +---------------------------+

  +---+---+---+---+---+---+---+---+
  | h | b | c | d | e | f | g | a |
  +---+---+---+---+---+---+---+---+
        ^                   ^
        +-------------------+

  +---+---+---+---+---+---+---+---+
  | h | g | c | d | e | f | b | a |
  +---+---+---+---+---+---+---+---+
            ^           ^
            +-----------+

  +---+---+---+---+---+---+---+---+
  | h | g | f | d | e | c | b | a |
  +---+---+---+---+---+---+---+---+
                ^   ^
                +---+

  +---+---+---+---+---+---+---+---+
  | h | g | f | e | d | c | b | a |
  +---+---+---+---+---+---+---+---+

Oder in Code
  for( j = 0; j < i / 2; ++j ) {
    char tmp = s1[j];
    s1[j] = s1[i-j-1];
    s1[i-j-1] = tmp;
  }

  

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

Bewertung
0 lesenswert
nicht lesenswert
Ich habe die C-FAQ um eine entsprechenden Abschnitt
ergänzt:

http://www.mikrocontroller.net/articles/FAQ#Eigene...

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank dass du dir die Zeit nimmst für diese detaillierten 
Erklärungen.

Wo wir grade bei Strings sind, noch zwei Fragen:

Folgendes funktioniert bei meinem Mikroprozessor einwandfrei:
char *s3;

sprintf(s3, "Hallo");

Dieses hier aber nicht:
char *s3;
int j=4;

sprintf(s3, "%d", j);

Woran kann das liegen?

Und wann bietet es sich an, den String gleich als Array zu deklarieren 
(char s3[5]), wann sollte man nur einen Zeiger deklarieren (char* s3)?

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In die erste sprintf-Anweisung muss natürlich noch eine DUmmy-Variable,

sprintf(s3, "Hallo", j);

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

Bewertung
0 lesenswert
nicht lesenswert
TechInfo wrote:
> Vielen Dank dass du dir die Zeit nimmst für diese detaillierten
> Erklärungen.
>
> Wo wir grade bei Strings sind, noch zwei Fragen:
>
> Folgendes funktioniert bei meinem Mikroprozessor einwandfrei:
>
>
char *s3;
> 
> sprintf(s3, "Hallo");
>
> Dieses hier aber nicht:
>
>
char *s3;
> int j=4;
> 
> sprintf(s3, "%d", j);
>
> Woran kann das liegen?

Weil beides falsch ist, nur beim ersten hast
du das Pech, dass es so aussieht als würde es
funktionieren.

sprintf möchte einen Speicherbereich in dem es das
Ergebnis ablegt. Ein Pointer ist aber eine Variable
die auf so einen Speicherbereich zeigen kann, selbst
aber diesen Bereich nicht zur Verfügung stellt.
  char s1[20];
  sprintf(s1, "Hallo");

Jetzt hat s1 einen Speicher*bereich* in dem es die Zeichen
ablegen kann.


> Und wann bietet es sich an, den String gleich als Array zu deklarieren
> (char s3[5]), wann sollte man nur einen Zeiger deklarieren (char* s3)?

Ein Array nimmst du dann, wenn du eine Speicherfläche brauchst
in der gearbeitet werden kann (zb. weil dort das Ergebnis einer
Stringbehandlung abgelegt werden muss).

Einen Pointer nummst du dann wenn
* Ein Array an eine Funktion übergeben werden soll.
  Arrays an sich kann man nicht übergeben. Stattdessen wird
  immer die Adresse des ersten Array Elementes übergeben.
  Und diese Adresse fängt die Funktion in einem Pointer
  auf (Pointer == Variable die eine Speicheradresse enthält).

* Du einen konstanten Text hast, der nicht verändert werden muss.
  Der Compiler muss ja natürlich den konstanten Text auch irgendwie
  in dein Programm einbauen. Das heist aber auch, so ein konstanter
  Text liegt schon irgendwo im Speicher. Nur hast du nicht das
  Recht diesen Text zu verändern.

  const char* Text = "Hallo World";

  Text ist ein Zeiger, ein Pointer, enthält also die Speicher-
  adresse wo denn im Speicher die Zeichenfolge "Hallo World"
  abgelegt wurde.


Merke: Ein Zeiger speichert nur eine Speicheradresse. Ob unter
dieser Speicheradresse auch tatsächlich gelesen und geschrieben
werden kann, sprich: ob unter dieser Speicheradresse auch wirklich
legal auf den Speicher zugegriffen werden kann, ist nicht das
Bier des Pointers.

Stell dir eine Bibliothek vor:
In den Regalen stehen Bücher. Nur manchmal steckt auch ein
Zettel dazwischen, auf dem steht: "Zu finden in Gang A, Regal 4"
Genau das ist ein Pointer. Er sagt dir wo die eigentliche Information
zu finden ist. Ob es einen "Gang A", "Regal 4" auch tatsächlich
gibt, interessiert aber den Pointer nicht. Es ist der Job des
Bibliothekars, äh Programmierers, dafür Sorge zu tragen, dass
dieser verweis auch tatsächlich richtig ist.

(An der Stelle Gang A, Regal 4 könnte dann ein Buch stehen. In
dem Buch gibt es dann einen weiteren Zettel "Gang A, Regal 5".
Dort findet sich dann ein weiterer Zettel, ... Obwohl also
die Bücher kreuz und quer über die komplette Bibliothek
verstreut sind, definieren diese Zettel eine eindeutige
Abfolge von Büchern (zb. Titel in alphabetischer Reihenfolge).
Muss ein neues Buch eingefügt werden, so stellt man es einfach
irgendwohin, wo gerade Platz ist. Beim alphabetischen Vorgänger
dieses neuen Buches kommt dann einfach ein neuer Zettel hinein
und in das neue Buch der Zettel vom Vorgänger. Dadurch ist
die Kette nicht unterbrochen und man hat beim Einfügen in die
Reihenfolge nicht viel Arbeit. Ansonsten müsste man nämlich
alle Bücherregale umräumen um Platz für das neue Buch zu schaffen.


Wichtig ist:
Ein Pointer ist nur ein Verweis in den Speicher. Eine Pointer-
variable speichert eine Speicheradresse. Es ist dein Job dafür
zu Sorgen, dass dieser Verweis auch auf tatsächlich verwenbaren
Speicher zeigt.

   char* s1;
   sprintf( s1, ...

Wo zeigt denn s1 hin? Auf welche Speicheradresse? Niemand
weiss es, weil Variableninhalte zufällig sind, wenn Variablen
auf die Welt kommen.

Aber

   char Buffer[20];
   char* s1;

   s1 = & Buffer[0];

Jetzt zeigt s1 auf den Beginn der Speicherfläche, die 'Buffer'
genannt wird. & ist der Adress-Operator und er liefert die
Speicheradresse einer Variablen.

Teil der Arraybehandlung in C ist es auch, dass Arrays in vielen
automatisch die Adresse auf das erste Element darstellen. Praktisch
immer dann wenn der Arrayname alleine (also ohne Indizierung)
vorkommt.

   s1 = & Buffer[0];

und
   s1 = Buffer;

sind also gleichwertig. Und daher ist es auch nicht notwendig

  sprintf( &Buffer[0], " .....

zu schreiben, sondern

  sprintf( Buffer, " ....

reicht völlig.


Wenn du also eine Funktion siehst, die als Arugment einen Pointer
haben möchte, heist das nicht notwendigerweise, dass du nur
eine Pointervariable anlegen musst und alles ist in Butter.
Meistens ist es so, dass dieser Argument-Pointer anzeigt, dass
die Funktion über diesen Pointer einen errechneten Wert ablegen
möchte. Nur muss man der Funktion dann aber auch die Speicheradresse
einer geeigneten Variablen geben, damit sie das tun kann.

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, plausibel. Aber auch mit einem Speicherbereich sieht es so aus:

Nach
char s2 [10];
sprintf(s2, "%i", j);

ist der String leer, aber
char s2[10];
sprintf(s2, "Hallo");

gibt er aus.

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

Bewertung
0 lesenswert
nicht lesenswert
TechInfo wrote:
> Ok, plausibel. Aber auch mit einem Speicherbereich sieht es so aus:
>
> Nach
>
>
> char s2 [10];
> sprintf(s2, "%i", j);
> 
>
> ist der String leer, aber
>
>
> char s2[10];
> sprintf(s2, "Hallo");
> 
>
> gibt er aus.

Dann musst du schon das komplette Programm posten.
Viele Fehler haben die Eigenart, sich an ganz
anderer Stelle bemerkbar zu machen als dort
wo sie auftreten.

Konkret kann man daher nur sagen: Du hast mindestens
einen Fehler im Programm. Die Symptome die du siehst sind,
dass
  char s2 [10];
  sprintf(s2, "%i", j);
nicht funktioniert.
Die Ursache dafür kann aber was ganz anderes sein.




Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
int main (void) {

...Präprozessoranweisungen....


  int z=278;
  char s1[10];
  
  sprintf(s1, "%i", z);
  puts(s1);

...Präprozessoranweisungen....

return 0;
}

  

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schreibe ich
sprintf(s1, "Hallo %i", z);

wird wiederum Hallo+Leerzeichen ausgegeben. Er kommt nur mit der 
Variablen nicht klar.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was für Präprozessoranweisungen werden denn da INNERHALB von main() 
verwendet?

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Programmiere einen Microblaze-Softcore.

Daten- und Instruktionscache werden aktiviert, falls das vorher im 
Design so festgelegt worden ist:
      #if XPAR_MICROBLAZE_0_USE_ICACHE
        microblaze_init_icache_range(0, XPAR_MICROBLAZE_0_CACHE_BYTE_SIZE);
        microblaze_enable_icache();
      #endif

      #if XPAR_MICROBLAZE_0_USE_DCACHE
        microblaze_init_dcache_range(0, XPAR_MICROBLAZE_0_DCACHE_BYTE_SIZE);
        microblaze_enable_dcache();
      #endif


Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK. Ich hatte schlimmes befürchtet, aber das ist legitim. Nur bedingte 
Compilation.

Manche mit C noch nicht sehr erfahrene Leute setzen munter #defines oder 
gar #include-Anweisungen irgendwo in den Quellcode ...

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann man darauf tippen, dass bei der Implementierung des sprintf für 
diesen Prozessor etwas nicht ok ist? printf funktioniert übrigens auch 
nicht.

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

Bewertung
0 lesenswert
nicht lesenswert
Probier mal %d anstelle von %i

> Kann man darauf tippen, dass bei der Implementierung des sprintf
> für diesen Prozessor etwas nicht ok ist?

Möglich wärs.

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe auch ein Problem mit den Funktionen atoi und atof.
char s[10]="1234";
int i=0;

i=atoi(s);

Er schreibt dann in i jeweils nur die letzte Ziffer, in diesem Fall 4. 
Das selbe bei atof.

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

Bewertung
0 lesenswert
nicht lesenswert
Wenn das tatsächlich stimmt, und ich habe keinen Grund
daran zu zweifeln, dann wäre das für mich mitlerweile ein
Grund den ganzen Kompiler, so wie er ist, von der Festplatte
zu löschen.

Wenn die Standardlibrary solch einfache Dinge nicht hinkriegt,
wer weiss welche Überraschungen dann noch warten.

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Blöd nur, dass er mir für die Diplomarbeit vorgegeben ist. Ich glaube 
ich werde mal bei Xilinx anrufen...

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.