Hallo,
ich hab zur zeit ein Problem und zwar hab ich ein Programm welches mit
dem keil-Compiler geschrieben wurde, ich benütze allerdings das
Avr-Studio, welches ja bekannter massen den Befehl "sbit" nicht kennt.
Hat zu fällig jemand ein Macro fürs AVR Sudio so das ich den befehl
verwenden kann?
oder kann mir jemand sagen in welcher form ich das Macro in meine
Headerdatei schreiben muss?
Viele Dank schon einmal im vorraus
ups stimmt wäre clever gewesen des gleich dazu zuschreiben
sbit led = 0xb0;
gibt dem entsprechendem Pin den Namen led, sprich man kann den Pin dann
direkt mit "led = 1" bzw "led=0" an/ausschalten
kann ich mit dem avr Studio auch irgendwie so einfach bestimmten Pins
einen namen geben und die dann mit "=1" an bzw "=0" ausschalten?
Mit AVR Studio hat das alles nichts zu tun.
Der AVR kennt erstmal keine Bitvariablen. Man kann das mit Bitfeldern
in C realisieren, wenn du das unbedingt willst, aber die AVR-Ports
sind natürlich erst einmal von Natur aus 8-bittig.
Vielleicht hilft es dir ja einfach, einen Wrapper-Makro zu schreiben?
Wow Danke!
Sehe ich es richtig das ich des auf jeden Port anwenden kann nur halt
immer den Port Buchstaben dem entsprechen anpassen muss?
Also für Led_rot an Port a und grün an Port d:
#define LED_rot (*(volatile struct test*)&PORTA).b3
#define LED_gruen (*(volatile struct test*)&PORTD).b2
Ja, das siehst du richtig.
Im obigen Beitrag fehlt noch:
typedef unsigned char byte;
Ich hatte das selbe Problem mit alten C51 Codes und keine Lust
alles zu ersetzen.
Ich hab dir noch nen Link aus dem Forum rausgesucht (die letzten 3
Beiträge).
Beitrag "#define in C"
Aufpassen musst du beim Einlesen eines Pins, da muss eben PINX und nicht
PORTX stehen.
Gruß Volker
hi
hier steht:
#define LED_rot (*(volatile struct test*)&PORTD).b3
in dem beitrag auf dem der link verweißt steht:
#define LED1 ((volatile struct test*)&PORTD)->b0
muss es jetzt ".b3" oder "->b3" heißen? oder ist des Jacke wie Hose?
Grüße
Tom
Oh, DANKE, danke!
Ich vermisse die Bitadressierung beim AVR auch sehr, bin bis dato aber
auch nicht auf was genialeres gekommen....
Clever!
Nur über
(((volatile struct test *)&r)->b##n)
muss ich erstmal ne Nacht lang schlafen :)
@yalu,
Kompliment, so ists wirklich noch übersichtlicher, habs zwar in der
Praxis noch nicht getestet, müsste aber gehen.
@Andreas
getreu mach dem Motto: Was nicht passt wird passend gemacht.
Das schönste an der Sache finde ich ist, dass es C-Konform ist, also
keine
Kompiler Spezialerweiterung, die nicht portierbar ist.
Gruß Volker
@Jörg:
Die Zeile
> MYLEDPORT &= ~MYLEDBIT;
in Deinem Beitrag ist recht interessant; sie erinnert mich an eine
Passage im avr-libc Manual (Punkt 7.3.21, S.197 im Manual Version
1.4.3), in der empfohlen wird, solche bitwise-Operationen sinngemäß wie
folgt zu schreiben:
> MYLEDPORT &= (unsigned char)~MYLEDBIT;
damit der Compiler 8-Bit-Operationen erzeugt, was ja genügt; andernfalls
(ohne den Cast) würde er 16-Bit-Operationen erzeugen ("promotion to an
int"); kannst Du das bestätigen? Und ist die Verwendung des Casts
vorteilhaft, oder ist es egal (bzw. würde die Optimierung -Os letztlich
das gleiche Ergebnis bringen - hab's jetzt nicht getestet)?
Günter
tatsache. interessant!
8.3.21 Why does the compiler compile an 8-bit operation that uses
bitwise operators into a 16-bit operation in assembly? Bitwise
operations in Standard C will automatically promote their operands to an
int, which is (by default) 16 bits in avr-gcc. To work around this use
typecasts on the operands, including literals, to declare that the
values are to be 8 bit operands. This may be especially important when
clearing a bit:
1
var&=~mask;/* wrong way! */
The bitwise "not" operator (~) will also promote the value in mask to an
int. To keep it an 8-bit value, typecast before the "not" operator:
edit:
im manual ist diese methode zwar auf der "Obsolete IO macros" liste,
aber funktionieren tut es auch.
1
#define sbi(port, bit) (port) |= (1 << (bit))
{quelle: avr-libc-user-manual-1.4.5.pdf S.48}
ich verstehe nur die begründung nicht ganz warum dieses makro entfernt
wurde:
"These macros became obsolete, as reading and writing IO ports can be
done by simply using the IO port name in an expression, and all bit
manipulation (including those on IO ports) can be done using generic C
bit manipulation operators."
nichts anderes geschieht in diesem makro, oder sehe ich hier was falsch?
allerdings sollte man, um die linie zu einzuhalten, folgendes schreiben:
Interresant, habs mal ausprobiert aber bin noch nicht ganz zufrieden.
Ich schreibe häufig code für den 8x51 und auf die hier beschriebene
Weise kann man sich in der Tat ne Menge Arbeit sparen.
Folgendes funktioniert aber leider nicht. Beispiel: Habe einen I/O als
Data definiert und shreibe:
DATA = meinbyte & 0x80;
Verwendet man ja des öfteren wenn man seriell etwas Aussenden will. Beim
MSP sowie 8x51 kein Problem. Mit dem hier beschriebenen Konstrukt gehts
in die Hose.
> DATA = meinbyte & 0x80;
Wenn "DATA" für ein Einzelbit steht, geht alles andere als Bit 0 über
die Wupper. Alternative:
DATA = (meinbyte & 0x80) != 0;
oder, äquivalent:
DATA = (meinbyte & 0x80) ? 1 : 0,
'übersetzt'. wenn ich mit meiner vermutung richtig liege, dann ist es
doch hinfällig, dass man nur "<<" castet: "[...] promote their operands
[...]" - also beide operanten.
castet der compiler den anderen operanten automatisch genauso?
pumpkin
> castet der compiler den anderen operanten automatisch genauso?
Bei (1<<n) kann ein Compiler ohne Kenntnis von n nicht wissen, dass das
Ergebnis in ein Byte passt, wird also ohne cast die normgerechte
16bit-Rechnung durchführen.
Er kann jedoch wissen, dass a|b nicht mehr Bits braucht als a oder b.
Das nützt ihm aber nur etwas, wenn er weiss das b ein Byte ist.
ich will mal davon ausgehen dass 'n' zum compile-zeitpunkt definiert und
<=7 ist. '(port)' soll auch acht bit haben. ansonsten würde das
gedankenexperiment nichtig sein.
pumpkin
Wenn ich mich recht entsinne, bezog sich die Bemerkung in der FAQ
nicht auf zur Compilezeit bekannte Konstanten, sondern auf eine
variable Schiebweite. Ja, auch sowas soll zuweilen vorkommen. ;-)
Ob und wie sich das Problem eventuell mit GCC 4.x entschärft hat,
hab' ich mir aber auch noch nicht angesehen.
Hab die Beiträge hier gerade mit großem Interesse gelesen und bin etwas
bestürzt das der AVR GCC so großzügig mit den AVR Ressourcen um sich
wirft wenn man nicht etliche Sachen beachtet.
Ich bin generell kein Fan von den Bitschiebereien in C und der
Lösungsansatz von yalu gefällt mir. Vielleicht könnte man das so weit
ausbauen das man damit Bits bearbeiten kann und der Compiler kein
Integer daraus macht um Ressourcen zu schonen und das ganze dann mal zum
AVR-GCC Standard. Ich bin leider nicht fit genug in C sonst würde ich
das selbst machen
> Hab die Beiträge hier gerade mit großem Interesse gelesen und> bin etwas bestürzt das der AVR GCC so großzügig mit den AVR> Ressourcen um sich wirft wenn man nicht etliche Sachen beachtet.
Und ich bin bestürzt, wie bereitwillig viele Leute allerlei propriertäre
und hoffnungslos unportable Erweiterungen der Sprache C verwenden, um
sich momentan etwas Arbeit zu ersparen. Zur Strafe bleiben sie dann für
ewig an ihrem Compiler festgenagelt, weil sie später merken, dass sie
nicht in C sondern in irgendwas entfernt ähnlichem programmiert haben.
GCC wurde für Workstations entwickelt und der C-Standard definiert
minimal 16bit Arithmetik. AVR ist überhaupt die einzige
8bit-Architektur, für die es den GCC gibt. Dafür ist er dann eigentlich
nicht übel. Und wenn andere Compiler den Standard ignorieren und auch
dann 8bittig rechnen, wenn der Standard 16bit vorschreibt - dafür kann
GCC nichts.
Ich weiß gar nicht was du willst. So wie ich das verstanden hab ich die
Lösung von yalu doch C-Konform, sollte also auch auf anderen Plattformen
laufen.
Außerdem glaube ich nicht das es mir viel hilft wenn ich auf Biegen und
Brechen alles überall schön ausführlich und C-Konform programmiert habe
und später das ganze auf eine andere Prozessorarchitektur portieren
will. Die IO Register auf einem ARM sehen anders aus und heißen auch
anders als auf einem AVR. Die Protierung eines AVR Programms auf einen
anderen Core ist IMHO IMMER mit viel Umschreiberei verbunden. Da könnte
so ein Makro am Ende sogar mehr helfen als schaden, oder? Außerdem wird
(zumindest für mich) der Code wesentlich besser lesbar wenn ich LED=1
schreiben kann statt dieses (1<<n) Bitgeschiebe.
Und wenn das Makro, so ganz nebenbei, auch noch dafür sorgt das der
Compiler ressourcenschonend mit Byte statt Int arbeitet bin ich
glücklich und zufrieden.
Und selbst wenn ich "propriertäre und hoffnungslos unportable
Erweiterungen" verwenden will ist das doch mein Bier, solange ich andere
damit nicht konfrontiere sondern nur mir selbst damit schade
Ich bezog mich da eher auf die im Thema genannten "sbit"-Spielchen und
Notationen wie "port.3". Und dieser ganze Thread wurde überhaupt nur
gestartet, eben weil sich jemand in einer proprietärer Erweiterung
verheddert hatte.
Wenn man "portabel" programmieren will muß man sowieso von vorn herein
die eigentliche Programmlogik und die Hardwarezugriffe streng
voneinander trennen (und wer macht sowas schon). Wenn man das Programm
dann tatsächlich mal protieren muß dann muß man sowieso den kompletten
Hardwarelayer neu programmieren. Ich bezweifle das es für einen AVR,
8051, PIC, ARM ... zb einheitliche UART Librarys gibt die alle das
gleiche Interface haben.
Außerdem finde ich Makros wie sbi/cbi durchaus auch legitim, auch wenn
SetBit/ClrBit vielleicht allgemeiner wären. sbi/cbi stammen ja aus dem
AVR Assembler Wortschatz. Solche Makros lassen sich doch in 5 Minuten in
jedem C Compiler nachbilden. Ich kenne Bitfelder (noch) nicht und weiß
nicht in wie weit die "C-Konform" sind und ob die bei allen C Compilern
zu finden sind. Falls nicht wären auch in dem Fall Makros die bessere
Wahl, die gibt es definitiv bei jedem Compiler.
Und was das Verhalten des Compilers angeht alles in Integer umzuwandeln:
ich kann den Grund dafür durchaus verstehen warum das so ist, aber auf
einem Ressourcenarmen System wie einem 8 Bit Controller sollte man doch
eher darauf Rücksicht nehmen die Ressourcen zu schonen. Aber da finde
ich es schon fast unzumutbar bei jeder Bitoperation "unsigned char" oder
von mir aus auch eine der Kurzformen hinschreiben zu müssen.
Und es ist doch auch nicht Sinn der Sache wenn ich nur wegen diesem
Compilerverhalten einen größeren AVR nehmen muß als eigentlich nötig.
Das mag im Hobbybereich vielleicht gehen, aber in der Industrie würde
dem Compiler der Vorzug gegeben der den kleineren Code produziert, auch
wenn der 1000€ kostet.
Da liegen die Prioritäten halt eher auf Ressourcenoptimierung und gut
lesbarer und wartbarer Code und weniger auf Portierbarkeit und
C-Konformität um jeden Preis. Den Mehraufwand zahlt einem nämlich keiner
Wenn du erstmal mit der Bitmanipulation in C vertraut bist, gibt's
keinen richtigen Grund mehr für die "simplen" Makros: Generationen von
C-Programmierern vor dir haben es verstanden, damit Bits zu verwürfeln
(schließlich war sowas von vornherein von K&R mit eingeplant).
Gejammer darüber, ach wie umständlich das doch sei (auch wenn am Ende
die beliebten CBI- und SBI-CPU-Befehle generiert werden) kommt da
lediglich aus dem Lager der AVR-Programmierer.
Wenn du den Schritt logisch vernünftig weitergehst (siehe yalu),
kommst du eher bei einer Art HAL (hardware abstraction layer) heraus
und abstrahierst auf dem Niveau des Zugriffs auf die tatsächlich
angeschlossene Peripherie.
Ich kann dir aus eigener Erfahrung auch sagen, dass der wesentliche
Nachteil von Dingen wie cbi- und sbi-Makros (abgesehen davon, dass
damit ein nicht-AVR-C-Programmierer schlicht nichts anfangen kann)
darin besteht, dass die Leute sie, sowie sie einmal da sind, dann nur
gedankenlos benutzen. Statt ein control register auf einmal mit all
seinen 8 Bits einzurichten, werden dann blindlings 8 cbi- und sbi-
Aufrufe draus gemacht...
> Außerdem finde ich Makros wie sbi/cbi durchaus auch legiti
Wo ist da ein Macro:
sbit led = 0xb0;
Das ist ein Compiler-Konstrukt.
cbi/sbi wie in früherer avrlibc sind ok, ebenso bitfields. Ich selber
mag bitfields nicht so, weil man dann doch immer wieder auch die
Möglichkeit benötigt, alles oder mehrere Steuerbis gleichzeitig zu
setzen, und dann gewöhnlich bei doppelter Definitionsarbeit landet:
einmal als bitfield, und einmal als Latte von #defines.
Statt dessen neige ich eher zu Jörgs Variante: Passend benannte
macros/inlines verstecken die Portoperation.
> bei jeder Bitoperation "unsigned char" oder> von mir aus auch eine der Kurzformen hinschreiben zu müssen.
Dann nimm -mint8. Jeder Compiler mit Repekt vor Standards wird den Typ
von 1<<n bei unbekanntem n als "int" ansetzen müssen. Soweit liegt es
fest. Wenn int dann 8bittig ist, wird es trivial.
Inwiefern er dann in der Lage ist, festzustellen, dass es letztlich egal
ist, ist Sache der Optimierung. GCC ist hinsichtlich Optimierung an sich
nicht übel. Aber dass die angenommenen 16bittigen Grundoperationen von
der 8bittigen Zielmaschine weiter aufgedröselt werden müssen, das ist
nicht so sein Ding. Willst du einen Compiler der auf Fisematentchen von
8bittern gut eingerichtet ist, dann lass die Finger weg von GCC, das ist
einfach nicht seine Baustelle.
Ich habe obigen Code letzthin mal durch GCC 4.1 laufen lassen. Der Shift
war bei unbekanntem n immer 16bittig, egal wie gecastet, aber danach
blieb es 8bittig. Nicht ideal, aber auch nicht schlecht.
Ich kenn die normalen Bitmanipulationen von C, aber ich mag sie einfach
nicht und kann (und vielleicht auch will, das geb ich zu) mich einfach
nicht daran gewöhnen. Die Schreibweise in C ist der Mathematik entnommen
und ich war nie gut in Mathe. Ich bin auch kein reiner AVR Programmierer
sondern ich habe schon zu C64 Zeiten angefangen zu programmieren und hab
seitdem diverse Prozessoren und Mikrocontroller programmieren müssen.
Aber meistens in Assembler. Vielleicht auch deshalb die Probleme mit den
Bitmanipulationen in C.
Wenn andere Leute damit nicht umgehen können ist das eine andere Sache.
Ich bin durchaus in der Lage in Bits, Bytes, HEX oder was auch immer zu
denken und das auch so zu programmieren. Für mich wäre ein
#define LED Bit(PortB, PB5);
LED=1;
einfach logischer, lesbarer und schlicht und ergreifend hilfreicher als
ein
#define LED_PORT PortB;
#define LED PB5;
LED_PORT |= (1 << (LED);
Ich kann ja das Bestreben, C-Konformen Code programmieren zu wollen, in
gewissen Grenzen verstehen, aber es hilft mir einfach nicht. Die
Begründung, das die Programme dann portierbar sind, finde ich nämlich
hinfällig weil die Unterschiede zwischen den Architekturen einfach zu
groß sind. Wie gesagt, wer wirklich protierbaren Code erreichen will
kommt um einen HAL nicht drumrum.
@A.K.
Ich werd die Variante von Jörg und die von Volker/yalu einfach mal in
der Praxis ausprobieren und mir dann das raussuchen was für mich besser
funktioniert.
Wie muß ich denn die beiden Varianten modifizieren das alles als Byte
angesehen wird? Da steh ich irgendwie auf dem Schlauch. Könnt Ihr mir da
grad mal helfen?
imho zu wünschen übrig lässt wenn man gerade verdrängt hat dass 'LED'
ein einzelnes bit ist. dann doch lieber:
1
bla|=(1<<LED);
meinetwegen auch mit cast, aber dann ist klarer was da wie, wo und wann
passiert. man muss sich am ende doch nur merken dass '|' setzt und '& ~'
löscht - mir ist unklar wie man sich dagegen sträuben kann.
>> Wie gesagt, wer wirklich protierbaren Code erreichen will>> kommt um einen HAL nicht drumrum.
das halte ich für ein gerücht. das macht das portieren bloss leichter
weil nur einzelne codeabschnitte bearbeitet werden müssen.
pumpkin
@pumpkin
Es gibt Situationen wo die übliche Schreibweise sicher Vorteile bringen
kann, aber für mich wäre "meine" Variante in den meisten Fällen
einfacher. Ich tue mich mit einer Wortsprache (zb ASM) einfach leichter
als mit der Symbolik von C. Ich hab viel in ASM programmiert und hab am
PC später auch lieber in Pascal/Delphi programmiert. Aber auf
Mikrocontrollern hat man halt kaum eine Wahl
>> Wie gesagt, wer wirklich protierbaren Code erreichen will>> kommt um einen HAL nicht drumrum.>das halte ich für ein gerücht. das macht das portieren bloss leichter>weil nur einzelne codeabschnitte bearbeitet werden müssen.
Dann hast du aber keinen portierbaren Code. Portierbarer Code hat keine
Hardwarezugriffe sondern ruft nur Funktionen auf die die
Hardwarezugriffe übernehmen. Und diese Funktionen müssen auf allen
Plattformen die gleiche Schnittstelle haben, also die gleichen Parameter
entgegennehmen und zurückgeben. Ein Code ist erst dann "portabel" wenn
man auf dem neuen System keine Änderungen vornehmen muß sondern einfach
in den Compiler packt und compilieren kann. Und aufgrund der teilweise
massiven Unterschiede in manchen Architekturen kann es selbst mit einem
HAL manchmal Probleme geben. Allein der Zugriff auf ganz normale IO
Ports ist auf einem ARM vollkommen anders als auf einem AVR und macht
einer Portierung schon schwierig.
Wenn ich an einem Programm stundenlang rumdoktorn muß bis es auf einem
neuen System läuft ist es für mich nicht portabel. Und da helfen mir die
C-Konformen Bitschiebereien auch nicht wirklich.
Die hier diskutierte Lösung ist aus meiner Sicht sehr sinnvoll und ich
werde Sie übernehmen.
Warum kann ein IAR, Keil, SDCC so etwas ohne probleme ? Weils kein
Problem ist. Nur beim AVR ist es umständlich weil er kein Einzelbit
kennt.
Diese Lösung hat immerhin dazu geführt das ich nun identischen Code bei
den MSP's, 8x51 und AVR's verwenden kann.
Danke dafür ;-))
> LED = 1;
Mach's doch gleich zu
LED(on);
Du sollst schließlich beim Lesen nicht erst drüber nachdenken müssen,
ob die LEDs in diesem System low-aktiv (häufig der Fall) oder
high-aktiv sind.
Es geht ja nicht spezifisch um LEDs sondern allgemein um Bits. Das
gleiche könnte man auch für Eingänge machen. Die können auch "activ low"
oder "active high" sein. Außerdem sind bei mir sowieso alle LEDs und
Taster active high
Mir wäre einfach mal wichtig eine "für mich" verständliche Lösung zu
finden die im Idealfall für eine einfache Bitoperation wirklich nur die
nötigen ASM Befehle erzeugt. Ich programmiere häufig für kleinere AVRs
und bin jetzt etwas verunsichert ob die gelegentliche Speicherknappheit
nur daran lag das der Compiler überflüssige Sicherheitsreserven
eingebaut hat.
Aus dem Grund möchte ich gerne die Version von Volker/yalu für mich
etwas anpassen so das gleich alles so eingebaut ist das auch wirklich
nur Bytes bearbeitet werden.
Ja, genau. Die will ich auch verwenden. Ich möchte jetzt nur noch wissen
ob in der Variante auch 16 Bit Schiebeoperationen erzeugt werden und
wenn ja wie man die vermeiden kann.
also wenn man im Assembler-Listing nachschaut findet man mit den
verwendetet Macros
#define sclad (*(volatile struct test*)&PORTD).b3
... sclad = 1;
sclad = 0;
...
602: 93 9a sbi 0x12, 3 ; 18
604: 93 98 cbi 0x12, 3 ; 18
wird also so umgesetzt, wie es sein soll. Von einer 16-Bit
Schiebeoperation
ist da nichts zu finden.
Gruß Volker
Vielen Vielen Dank. Das hilft mir jetzt denke ich echt weiter.
Aber mir ist noch was anderes aufgefallen. Wie kann bei einem so
einfachen Programm auf 152 Byte (ohne Optimizer. Mit sind es 144) kommen
(WinAVR 20070122)?
- Interruptvektoren
- C-Startup-Code (Löschen von .bss, Laden von .data)
Regel #1: degenerierte Testfälle werden dir nie eine sinnvolle
Aussage bringen. Ein leeres main() ist halt das typische
Beispiel dafür.
Es ist ja nicht "leer" ;)
Interruptvektoren ist klar. Wird da immer die komplette Tabelle
eingetragen? Vermutlich.
C-Startup-Code is mal ne Info die ich noch nicht hatte. Ohne solche
"degenerierten Testfälle" wäre ich vermutlich nie darauf gekommen das es
sowas gibt und würde mich immer nur über große Programme wundern. Man
muß ja lernen
Naja, auf einem Controller mit nur 128 Bytes ROM wirst du kaum C
benutzen. ;-) Auf allen anderen fällt der Startup-Code im Vergleich
zum Rest nicht mehr groß ins Gewicht, da desse Größe ja praktisch
konstant ist.
Ja, die Vektoren werden immer alle eingebunden. Sind auf einem
ATmega1281 auch schon mal (56 + 1) Stück zu je 4 Bytes, also 228
Bytes allein für die Vektortabelle. Würde in den fiktiven 128-Byte-
Controller also schon gar nicht mehr passen...
Etwas offtopic vielleicht, aber ich kam darauf, weil in diesem Thread
viel über vom Compiler generierte 16-Bit-Operationen gescholten wurde
und weil A.K. weiter oben den Vorschlag machte, -mint8 zu verwenden.
Irgendwo (kann sein im K&R, vielleicht auch im C-Standard) stand, dass
die Größe von int die "natürliche" Wortlänge des Zielprozessors sein
sollte. Bei manchen Prozessoren (wie dem MC68000) kann diese
"natürliche" Wortlänge je nach Geschmack unterschiedlich sein (16 oder
32 Bit), aber beim AVR kann sie eindeutig auf 8 Bit festgelegt werden.
Deshalb sollte eigentlich ein int 8 Bit lang sein, was durch die
Option -mint8 erreicht werden kann. Damit gehören alle ungewollten
16-Bit-Operationen der Vergangenheit an, auch ohne Type-Casts oder
Umstellung der Auswertereihenfolge.
(Mögliche) Nachteile bei der Verwendung von -mint8:
- ein Integertyp (und sein Unsigned-Pendant) geht verloren, bei
älteren GCCs der 32- bei neueren der 64-Bit-Typ. Aber wer macht auf
dem AVR schon etwas mit 64-Bit?
- Ich bin mir nicht sicher (und habe gerade nicht die Zeit
nachzuschauen, aber Jörg weiß es aus dem Kopf ;-)), ob die avrlibc
"mint8-aware" ist. Möglicherweise genügt es, sie mit -mint8 neu zu
bauen.
@yalu:
> ...aber beim AVR kann sie eindeutig auf 8 Bit festgelegt werden.
Nein, kann sie nicht. Der Standard besagt (als Einschränkung zu der von
Dir ein paar Zeile weiter oben wiedergegebenen Aussage), dass int und
short mindestens 16 Bit lang sein müssen.
yalu wrote:
> - Ich bin mir nicht sicher (und habe gerade nicht die Zeit> nachzuschauen, aber Jörg weiß es aus dem Kopf ;-)), ob die avrlibc> "mint8-aware" ist. Möglicherweise genügt es, sie mit -mint8 neu zu> bauen.
Ist sie nicht, und kann sie nicht sein. Daher kann man sie auch nicht
,,einfach'' mit -mint8 neu übersetzen.
Der Grund, dass sie es nicht sein kann, liegt wieder in den
Mindestforderungen des C-Standards. Um nur einfach ein Beispiel
zu nennen, das mir sofort einfällt: die Behandlung des Typs "char"
in den Standardfunktionen erwartet außer den 256 Zeichen, die da
reinpassen außerdem noch, dass es einen out-of-band-Wert für EOF
gibt. Daher übergeben/-nehmen diese Funktionen ein int, das
folglich mindestens 257 Werte unterscheiden können muss.
Die Option -mint8 geht nur, wenn man auf die avrlibc weitgehend
verzichtet. Was machbar ist, vor allem bei eher kleinen Projekten.
Aber auch wenn sie nicht einsetzbar ist, kann sie in einer Hinsicht
trotzdem nützlich sein: um rauszukriegen, wieviel man dabei sparen
würde. So katastrophal ist das nämlich nicht ;-).
> Irgendwo (kann sein im K&R, vielleicht auch im C-Standard) stand, dass> die Größe von int die "natürliche" Wortlänge des Zielprozessors sein> sollte.sollte, ja. Sie muß aber mindestens 16 Bit sein.
> die Behandlung des Typs "char" in den Standardfunktionen erwartet> außer den 256 Zeichen, die da reinpassen außerdem noch, dass es einen> out-of-band-Wert für EOF gibt. Daher übergeben/-nehmen diese> Funktionen ein int, das folglich mindestens 257 Werte unterscheiden> können muss.
Das ist kein wirklich passendes Beispiel, denn es wäre durchaus erlaubt,
wenn char und int beide 16 Bit breit wären und EOF ein gültiger
char-Wert wäre. Deshalb gibt's z.B. auch die Funktion feof(). Mit einem
Check des Rückgabewertes von fgetc() auf EOF alleine ist das Erkennen
eines Dateiendes nicht 100% portabel.
> Daher übergeben/-nehmen diese Funktionen ein int, das folglich> mindestens 257 Werte unterscheiden können muss.
Jetzt ist mir halbwegs klar, woher die Forderung nach mindestens 16
Bit für ein int kommt. Vielen Dank.
> Das ist kein wirklich passendes Beispiel, denn es wäre durchaus> erlaubt, wenn char und int beide 16 Bit breit wären und EOF ein> gültiger char-Wert wäre. Deshalb gibt's z.B. auch die Funktion> feof(). Mit einem Check des Rückgabewertes von fgetc() auf EOF> alleine ist das Erkennen eines Dateiendes nicht 100% portabel.
Gibt es denn passendere Beispiele?
@Jörg Wunsch
@Rolf Magnus
Nochmal offtopic, weil mich die Sache mit den unterschiedlichen
int-Typen jetzt einfach interessiert:
Ich habe mir gerade den Standard
ISO/IEC 9899 Second edition 1999-12-01
Programming languages - C
reingezogen.
Da habe ich keine Informationen darüber gefunden, dass ein int
mindestens 16 bit groß sein muss. Habe ich da etwas übersehen, oder
gab es diese Forderung nur in älteren Standards?
Natürlich leuchtet nach Jörg's Argumentation ein, dass ein int größer
als ein char sein sollte (wobei dann bei einer char-Größe von 8 bit
aber auch 9 bit reichen würden), aber vielleicht ist auch Rolf's
Aussage richtig, dass der EOF-Rückgabewert von fgetc() für sich
alleine kein hinreichendes Kriterium für das Erreichen des Dateiendes
(bzw. einen Fehler) darstellt.
Ich habe jedenfalls für beide "Theorien" keine Hinweise gefunden und
bin jetzt etwas verwirrt.
Vielleicht könnt ihr mir da heraus helfen :-)
-- minimum value for an object of type int
INT_MIN -32767 // -(215-1)
-- maximum value for an object of type int
INT_MAX +32767 // 215-1
-- maximum value for an object of type unsigned int
UINT_MAX 65535 // 216-1
@A.K.
Ah, nicht die minimale Bitzahl, sondern der minimale Wertebereich ist
angegeben. Da hätte ich wohl alles etwas genauer durchlesen müssen :-)
Danke für den Hinweis! Habe auf jden Fall wieder was dazu gelernt.