hello,
schon wieder ein Problem. Dieses mal glaube ich zu wissen, woran es
liegt. Nur leider weiß ich nicht, wie ich es lösen soll.
1
#define iBufferMax 16 // max 16 Chars im Ringbuffer
2
voidmain(void)
3
{
4
chariX;
5
iX=5%iBufferMax;// hat den Wert 1280!!!
6
}
Ich gehe mal davon aus, dass das irgendetwas mit einem Überlauf zu tun
hat. Wie kann man denn den verhindern?
Ich will für iBufferMax unbedingt eine Konstante verwenden. Mit const
habe ich es auch schon versucht, aber damit kann ich nicht arbeiten,
weil dann das folgende nicht funktioniert:
1
constchariBufferMax=16;// max 16 Chars im Ringbuffer
2
voidmain(void)
3
{
4
chariX=5%iBufferMax;// 1280
5
charaY[iBufferMax];// <- mag C nicht
6
}
(Ich hoffe, ich habe das jetzt richtig verkürzt hier reingetippt.)
Ich bräuchte also define. Aber wie kann ich das dann verwenden??
mfG 'Ringbuffer-Heinz' :)
Ist mir schon klar, dass es zwischen define und const einen Unterschied
gibt. define wird schon beim Kompilieren aktiv. Der Kompiler ersetzt
dann die Platzhalter durch deren Werte (sofern ich das richtig
verstanden habe). Und const wird erst zur Laufzeit aktiv. Und darum
funktioniert das auch beim Array nicht.
Aber ich bekomme wirklich 1280 ausgegeben. Habe ich mit Keil-C
kompiliert, in uC geladen und dann den Wert mittels printf ausgegeben
und angeschaut.
Aber ich versuchs gleich noch einmal. Aber beim 4ten mal wird wohl auch
nichts anderes rauskommen ... :)
Auf was für einer Zielplattform arbeitest du denn, wenn ein "char"
bei dir den Wert 1280 annehmen kann? ;-) Davon abgesehen, dass
"char" hier der denkbar ungünstigste Datentyp ist, denn dessen
Vorzeichenhaftigkeit oder -losigkeit ist vom Standard nicht definiert.
Du solltest über uintfast8_t oder uint8_t (aus <stdint.h>) mal
nachdenken.
Dein Hauptproblem wird aber sein, dass du die Indexrechnung vorzeichen-
behaftet machst. Die beiden Konstanten 5 und 16 sind vom Typ `int'.
Du solltest deine Rechnung als `unsigned int' machen. Um die
Konstante unsigned werden zu lassen, kannst du ihr ein `u' (klein
oder groß) anhängen, also beispielsweise:
1
#define iBufferMax 16u
Es genügt, das einer von beiden Teilausdrücken des Terms unsigned
ist, da sich `unsigned int' über `signed int' durchsetzt bei der
Rechnung. Was aber nicht genügt (und was gern verwechselt wird)
ist, dass die Ergebnisvariable (also die linke Seite der Zuweisung)
einen unsigned-Typ erhält; die Rechnung auf der rechten Seite (und
damit die Festlegung, ob diese vorzeichenbehaftet ist oder nicht)
erfolgt, noch bevor ggf. über eine Typkonvertierung für die
Zuweisung entschieden werden muss.
Heinz B. schrieb:
> Aber ich bekomme wirklich 1280 ausgegeben. Habe ich mit Keil-C> kompiliert, in uC geladen und dann den Wert mittels printf ausgegeben> und angeschaut.
Ein char KANN nicht 1280 sein.
Zumindest nicht auf deinem System :-)
Also wird das Problem nicht beim % liegen, sondern bei der Ausgabe :-)
Was auch gerne übersehen wird, sind die Effekte, die entstehen, wenn
Zahlen übereinander auf einem LCD ausgegeben werden.
Aus einer am LCD stehen Zahl "1080" und einem darüber geschriebenen "12"
wird dann ganz schnell "1280"
Und noch was.
Gewöhn dir gleich von Anfang an, den Datentyp char aussschliesslich nur
für Variablen zu benutzen, die im Sinne eines Character (also eines
Zeichens) benutzt werden.
Willst du einen 'kleinen Integer' haben, dann IMMER entweder "signed
char" oder "unsigned char", je nachdem ob du ein Vorzeichen brauchst
oder nicht.
Bei char kann sich der Compiler aussuchen, ob er das als signed oder
unsigned ansehen will. Und je nachdem kann das manchmal ganz schön ins
Auge gehen.
p.s.: Nein, du hast noch irgendwo anders ein Problem. Klar ergibt
5 mod 16 wieder 5. Wenn du dir 1280 mal hexadezimal ansiehst, sind
das 0x500. Irgendwie werden wohl bei dir da Bytes verwuselt...
(Auch wenn meine Analyse weiter oben falsch war, lasse ich sie mal
drin, denn ich bin nach wie vor der Meinung, dass man die Index-
rechnung eines Ringpuffers normalerweise vorzeichenlos machen
sollte.)
> Aber ich bekomme wirklich 1280 ausgegeben. Habe ich mit Keil-C> kompiliert, in uC geladen und dann den Wert mittels printf ausgegeben> und angeschaut.
Ein char auf einem uC kann niemals den Wert 1280 annehmen, dafür müsste
es mindestens 11 Bits groß sein. Vermutlich hast Du mit %d ausgegeben
und Keil unterscheidet bei der printf-Übergabe (nicht ganz
standardkonform) zwischen 8 Bits und int. Garbage in, garbage out.
#include<reg517a.h> // special function register declarations
3
#include<stdio.h> // prototype declarations for I/O function
4
#include<string.h>
5
6
#define iBufferMax 16 // max 16 Chars im Ringbuffer
7
8
voidmain(void)
9
{
10
chariX;
11
12
iX=5%iBufferMax;
13
printf("%d",iX);// mit %c habe ich nichts bekommen, bei %d bekomme ich 1280 angezeigt
14
15
while(1)
16
{
17
}
18
}
Irgendwas passt mit den Datentypen nicht. Ich versuche jetzt mal den
Vorschlag vom Jörg. Dass diese define-Sachen automatisch vom Typ int
sind, wusste ich noch nicht.
Logo. %c würde als Character ausgeben.
Es gibt aber auf deinem Ausgabegerät kein sichtbares Zeichen, das den
ASCII Code 5 hätte.
1
printf("%d",iX);// mit %c habe ich nichts bekommen, bei %d bekomme ich 1280 angezeigt
das %d im Formatstring will einen int haben. Dagegen kannst du nichts
machen. Aber du kannst aus dem char einen int machen :-)
1
printf("%d",(int)iX);// mit %c habe ich nichts bekommen, bei %d bekomme ich 1280 angezeigt
Eigentlich sollte diese Umwandlung nach int den C-Regeln entsprechend
automatisch gemacht werden, aber da hat wohl Keil im Sinne der Effizenz
den Sprachstandard ein wenig gebogen :-)
Heinz B. schrieb:
> Vorschlag vom Jörg. Dass diese define-Sachen automatisch vom Typ int> sind, wusste ich noch nicht.
Das hat mit #define nichts zu tun.
Jede ganze Zahl ist in C automatisch immer ein int.
Es sei denn die Zahl ist zu gross für einen int. Dann ist sie
automatisch ein long.
Heinz B. schrieb:
> Aber eigentlich wollte ich ja keinen int. char würde vollkommen reichen.
Du meinst unsigned char :-)
> Muss nur von 0 bis ... hm ... kein Ahnung ... vielleicht 16 ... gehen.
Du kannst ja die Variable ruhig auf unsigned char lassen.
Nur zur Ausgabe musst du temporär einen int für printf daraus machen :-)
(Es sei denn Keil hat dem printf ein Formatzeichen für Character
spendiert, welches einen signed/unsigned char in seiner numerischen Form
ausgibt. Also das Äuivalent von %d für char -> Compiler Doku studieren)
Heinz B. schrieb:
> Aber eigentlich wollte ich ja keinen int.
Das ist aber bei printf der kleinste Datentyp, mit dem man eine
Ganzzahl ausgeben lassen kann. Daher musst du ihn zumindest für
deine Ausgabe (die ja vermutlich nur eine Debug-Ausgabe ist, also
später wieder verschwindet) in int oder unsigned int wandeln.
> char würde vollkommen reichen.
Nein. Ein char ist ein Zeichen, ein druckbares, oder eben auch
nicht, wie das Zeichen <ENQ> in deinem Beispiel (falls du es nach
dem Ausgeben als ASCII interpretierst).
Wie dir oben schon gesagt worden ist, für kleine Ganzzahlen nimmt
man uint8_t/uintfast8_t (falls dein Compiler nach 11 Jahren wenigstens
so viel C99 beherrscht, dass er ein <stdint.h> mitliefert) oder
ersatzweise die Typen unsigned char bzw. signed char, aber niemals
einfach so "char".
> Dass diese define-Sachen automatisch vom Typ int> sind [...]
Sind sie nicht. Bitte vergegenwärtige dir als allererstes, was
genau ein #define ist. Es ist eine pure Textersetzung, die da
gemacht wird. Die hat (im Rahmen des #define) noch gar keinen
Typ. Was aber vom Typ int ist, ist die Konstante ("integer
literal" im Englischen) 5, genauso wie die Konstante 16.
[Edith: da hat mich der Karl Heinz mal wieder überholt...]
Hm ... ich glaube, ich habe das Problem gefunden.
Habe jetzt alles auf unsigned int umgestellt.
Mit der Ausgabe
printf("%u",iX);
bekomme ich nichts (wie beim Versuch mit Datentyp char). Mit der Ausgabe
printf("xxx %u",iX);
aber genau das richtige.
So ein Käse!
Bitte zeige immer das komplette Programm!
Geht auch viel einfacher als einzelne Teile abzutippen:
Im Editor markieren (die meisten Editoren unterstützen Strg+A für "Alles
markieren". Dann Strg+C für 'In die Zwischenablage kopieren'. Wechseln
hier ins Browserfenster und im Texteingabefeld Strg+V für 'Aus der
Zwischenablage einfügen'. Und schwupps hast du mit 3 Tastendrücken
deinen Code vollständig und fehlerfrei ins Forum übertragen.
C ist zum Verzweifeln. Wenn ich das mit dem Ringbuffer habe, schaue ich
das nicht mehr an :(
Ich versuche immer noch, es irgendwie mit char hinzubekommen. In diesem
Fall mit unsinged char:
Heinz B. schrieb:
> Mit der Ausgabe> printf("%u",iX);> bekomme ich nichts (wie beim Versuch mit Datentyp char). Mit der Ausgabe> printf("xxx %u",iX);> aber genau das richtige.
Sagen wir mal so: es wäre nicht der erste Bug in einem Compiler der
Firma Keil, falls dem wirklich so ist.
Nein, normal ist das nicht, beide Ausgaben sollten sich nur im
Vorhandensein bzw. Fehlen von "xxx " unterscheiden.
>> printf("xx %d", (int)iX);
Ja, damit gehts. Danke! :)
Aber ich bleibe trotzdem dabei. Den Ringbuffer versuche ich noch fertig
zu machen, aber dann ist Schluss mit C.
Karl heinz Buchegger schrieb:
> Von uns hier hat niemand diesen Compiler
Und ob man ihn nach derartigen Ungereimtheiten freiwillig benutzen
würde, bleibt mal dahin gestellt. ;-)
Heinz, du solltest nicht C (das gewiss seine Eier hat) mit der
Qualität dieses Compilers gleich setzen. Vielleicht probierst du's
ja beim nächsten Mal mit einem Compiler, der ein wenig mehr Wert
auf Konformität zum C-Standard legt...