Forum: Compiler & IDEs Wertebereich von uint16_t?


von Alexander S. (knut740)


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

von Grrrr (Gast)


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.

von Alexander S. (knut740)


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

von Peter D. (peda)


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

von Rufus Τ. F. (rufus) Benutzerseite


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.

von Mark .. (mork)


Lesenswert?

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

MfG Mark

von Grrrr (Gast)


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.

von Rufus Τ. F. (rufus) Benutzerseite


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.

von Alexander S. (knut740)


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.

von Rolf M. (rmagnus)


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.

von Rufus Τ. F. (rufus) Benutzerseite


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.

von Mark .. (mork)


Lesenswert?

@Alexander

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

MfG Mark

von (prx) A. K. (prx)


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.

von Rufus Τ. F. (rufus) Benutzerseite


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.

von Robert F. (fastred)


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.

von Karl H. (kbuchegg)


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.

von Hc Z. (mizch)


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.

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.