www.mikrocontroller.net

Forum: Compiler & IDEs Wertebereich von uint16_t?


Autor: Alexander Schmeil (knut740)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich stehe etwas auf dem Schlauch:

uint16_t sollte doch einen Wertebereich vom 0 bis 65535 haben.

Bei mir reicht es aber nur bis 2^15, d.h., wenn ich eine größere Zahl 
per UART übertrage, dann ist bei 32767 Schluß, danach kommt ein 
Minuszeichen und es zählt wieder rückwärts - wie es bei einem signed 
geschieht.

Kann denn der gcc-Compiler mein uuuu-int16_t nicht lesen?

Gruß
Alexander

Autor: Grrrr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alexander Schmeil schrieb:
> wenn ich eine größere Zahl
> per UART übertrage,

Das deutet darauf hin, das Du bei der Vorbereitung für die Übertragung 
oder beim speichern auf der Empfängerseite was anderes machst als es 
Deine Absicht ist. Gib uns diesbezüglich Details und Code.

Autor: Alexander Schmeil (knut740)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Glaube ich auch, ich habe probeweise die Definition des Array auf 
uint32_t geändert und trotzdem bleibt die Begrenzung bei 2^15.

Also, es ist in einem Programm-Module ein Array definiert mit
int16_t cts[16];.

In einem anderen Modul steht dann
extern uint16_t cts[16];
In dieses Array legt das Programm die ermittelten Werte ab, im 
vorliegenden Testfall habe ich die Werte um 32367 manuell eingetragen.

Dann kommt die Ausgabe über UART

char mw_ascii[5];  // Ascii-Wert von cts[i]
itoa(cts[i], mw_ascii, 10);
uart_puts(mw_ascii);

Beim Schreiben dieser Antwort ist mir aufgefallen, was ich falsch 
gemacht habe: das Nadelöhr ist wohl die Definition der Variablen 
mw_ascii[],
wo es an der nötigen Bandbreite fehlt.

Ich glaube, wenn ich das ändere, wird es funktionieren.

Gruß
Alexander

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alexander Schmeil schrieb:
> char mw_ascii[5];  // Ascii-Wert von cts[i]
> itoa(cts[i], mw_ascii, 10);
> uart_puts(mw_ascii);

Der Compiler macht nur einfach genau das, was Du ihm sagst.

Wenn Du ihm "utoa() sagen würdest, macht er es auch.


Peter

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

Bewertung
0 lesenswert
nicht lesenswert
Nein, das Problem liegt daran, daß Du itoa verwendest.

Was auch immer Du itoa übergibst, es interpretiert es als int - was 
auf Deinem System einem int16_t ist.

Autor: Mark .. (mork)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Funktion itoa erwartet eine int-Zahl, und int ist immer signed. 
Benutze stattdesssen utoa.

MfG Mark

Autor: Grrrr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alexander Schmeil schrieb:
> int16_t cts[16];.

Häh. Ich dachte uint16?

Alexander Schmeil schrieb:
> In einem anderen Modul steht dann
> extern uint16_t cts[16];

Hmm. An sich würde ich vom Linker erwarten, das er meckert weil die 
Typen nicht übereinstimmen. Denn uint16_t ist ungleich int16_t.
Ändere das, das ist sauberer.

Der eigentliche Knackpunkt aber wird die Verwendung von itoa sein. Lies 
Dir mal die Beschreibung durch. Es erwartet ein int und kein unsigned 
int. Entsprechend verhält es sich auch. Verwende doch einfach utoa.

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

Bewertung
0 lesenswert
nicht lesenswert
> An sich würde ich vom Linker erwarten, das er meckert weil die
> Typen nicht übereinstimmen.

Der Linker macht keine Typüberprüfungen, der sieht nur nach Symbolnamen. 
Und da das hier C und nicht C++ ist, haben die Symbolnamen keine 
Typinformation.

Autor: Alexander Schmeil (knut740)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Meine Vermutung, es könne an der Variablen mw_ascii liegen, waren 
natürlich unsinnig, für ascii reicht char völlig aus.

Mit utoa statt mit itoa funktioniert es aber bestens!

Vielen Dank für Eure schnelle Hilfe.

Alexander


PS Gibt es irgendwo eine Dokumentation, in der solche Funkltionen und 
ihre Parameter aufgelistet sind? Das itoa() hatte ich seinerzeit nur 
gefunden, weil ich den Namen anderswo schon mal gelesen hatte.

Autor: Rolf Magnus (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rufus t. Firefly schrieb:

> Und da das hier C und nicht C++ ist, haben die Symbolnamen keine
> Typinformation.

Auch in C++ wäre das (zumindest bei GCC) so. Die Symbolnamen werden 
nicht generell um Typinformationen erweitert, sondern nur dort, wo das 
nötig ist, z.B. bei Funktionen, wo man Parameter-Typen für die 
Überladung unterscheiden können muß.

Alexander Schmeil schrieb:
> PS Gibt es irgendwo eine Dokumentation, in der solche Funkltionen und
> ihre Parameter aufgelistet sind? Das itoa() hatte ich seinerzeit nur
> gefunden, weil ich den Namen anderswo schon mal gelesen hatte.

Vermutlich in der Dokumentation der Bibliothek, die diese Funktion 
bereitstellt, welche auch immer das sein mag.

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

Bewertung
0 lesenswert
nicht lesenswert
> Auch in C++ wäre das (zumindest bei GCC) so.

Du hast natürlich recht, warum auch sollte eine Namensdekoration von 
nicht überladbaren Symbolen erfolgen?

Wobei sie bei solchen Fehlern wie dem hier praktisch wäre.

Der übrigens hätte vermieden werden können, wenn die Headerdatei, in der 
das Array als extern deklariert wurde, in das Modul mit eingebunden 
worden wäre, in dem das Array definiert wird.

Dann hätte der Compiler meckern können.

Autor: Mark .. (mork)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Alexander

Die Doku für die avr-libc findet sich unter 
http://www.nongnu.org/avr-libc/user-manual/modules.html

MfG Mark

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rufus t. Firefly schrieb:

> Du hast natürlich recht, warum auch sollte eine Namensdekoration von
> nicht überladbaren Symbolen erfolgen?
>
> Wobei sie bei solchen Fehlern wie dem hier praktisch wäre.

Wird dadurch nicht besser, im Gegenteil. Dann kriegt man u.U. mehrere 
separate Variablen gleichen Namens und wundert sich, warum die gleiche 
Variable in zwei Programmmodulen unterschiedliche Werte hat. Das ist mit 
Absicht so implementiert.

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

Bewertung
0 lesenswert
nicht lesenswert
Hmpf, da hast Du natürlich recht. Hier hätte es allerdings geholfen, 
weil der Linker ein nicht aufgelöstes Symbol gemeldet hätte, nämlich 
das, was mit extern nur deklariert wurde.

Naja, man muss halt in C schon eine gewisse Disziplin entwickeln.

Autor: Robert F. (fastred)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
bin über die Suche über diesen Thread gestolpert und möchte folgende 
Beobachtung anmerken, die ich mit avr-gcc 4.3.3 mit Target atmega8 
gemacht habe:

itoa auf uint8_t -> liefert 0 - 255, überlauf etc alles scheint ok
itoa auf uint16_t -> liefert -32k - +32k ... Wertebereich wird also 
anders - für *i*toa korrekt - wiedergegeben

also ein bisschen Inkonsistent. Daher ist mir erst bei der verwendung 
von uint16_t Variablen aufgefallen, das ich itoa auf unsigned Variablen 
loslasse. böse! pfui!

utoa auf uint16_t liefert wie erwartet korrekte Ergebnisse.

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

Bewertung
0 lesenswert
nicht lesenswert
Robert F. schrieb:
> bin über die Suche über diesen Thread gestolpert und möchte folgende
> Beobachtung anmerken, die ich mit avr-gcc 4.3.3 mit Target atmega8
> gemacht habe:
>
> itoa auf uint8_t -> liefert 0 - 255, überlauf etc alles scheint ok
> itoa auf uint16_t -> liefert -32k - +32k ... Wertebereich wird also
> anders - für *i*toa korrekt - wiedergegeben
>
> also ein bisschen Inkonsistent.

Nö, überhaupt nicht.
Da ein uint8_t in einen int hineinpasst, und zwar mit allen Werten, ist 
es genau das was zu Erwarten ist.

itoa will einen int!
wenn du einen uint8_t hast, dann wird der zunächst auf einen int 
hochgehoben. Und da das ohne Probleme geht, bleiben alle Werte von 0 bis 
255 erhalten.

Ein uint16_t passt aber nicht mit allen Werten in einen int.

Du gehst davon aus, dass sich itoa irgendwie magisch an den übergebenen 
Parameter anpasst. Das passiert aber nicht. Es wird versucht, das was du 
angibst in einen int zu verwandeln und erst dieser int geht dann an 
itoa. Was du siehst, ist eine direkte Konsequenz dieses impliziten 
Casts.

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Robert F. schrieb:
> itoa auf uint8_t -> liefert 0 - 255, überlauf etc alles scheint ok
> itoa auf uint16_t -> liefert -32k - +32k ... Wertebereich wird also
> anders - für *i*toa korrekt - wiedergegeben
>
> also ein bisschen Inkonsistent.

Genaugenommen ist das nicht inkonsistent.  Da der Prototyp von itoa 
bekannt ist, hast Du in beiden Fällen einen impliziten Cast nach int. 
Und ein Cast (uint8_t) -> (int) geht nunmal unfallfrei, da alle für 
uint8_t möglichen Werte in einen int passen, bei einem (uint16_t) -> 
(int) muss es den beobachteten Überlauf geben.

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.