Schonmal von Google deine Warnung suchen lassen? Kurzfassung: strcpy erwartet char*, du übergibst aber volatile char*. So sollte es ohne Warnung gehen: strcpy((char*)mastercode, "xxx")
--
Frank Buss, http://www.frank-buss.de
piano and more: http://www.youtube.com/user/frankbuss
pgm_read_byte_far erwartet die Adresse wohl als Integer des Typs uint32_t und nicht als Pointer, der zudem bei Dir vermutlich nur 16 Bit groß ist. Wenn das an der Stelle trotzdem seine Richtigkeit hat, kannst Du die Meldung mit einem expliziten Typecast loswerden.
Vor allem hat der Compiler recht. Du weist einem Pointer auf uint8_t die Adresse eines uint16_t zu. Wenn Du nur Low- und Highbyte des
16-Bit-Integers haben willst, warum nutzt Du dann nicht die Operatoren
Das w=FCrde ich, gerade bei Anf=E4ngern in C, nicht so sehen. Es gibt=20 gen=FCgend Fallen, die C einem Anf=E4nger stellt und auf die der Compiler= =20 hoffentlich mit einer Warnung reagiert. Gerne gemachte Fahler: if(x =3D y) ...; // warnung: Zuweisung in if-Bedingung
char ch =3D 129; int x =3D ch; // welchen Wert hat x?=20
Ich habe mir angewöhnt, gcc nur noch mit -Wall -Werror aufzurufen.
Das zwingt einen dazu, bspw. casts explizit hizuschreiben. Das ist dann eine gute Gelegenheit, sich bewußt zu machen, was man damit macht.
Und für die Fälle, in denen der Compiler nicht erkennen kann, daß eine Variable aufgrund des Programmablaufs auf jeden Fall initialisiert wird, gibt es ja die bekannten
Aber selbst solche Warnungen sind berechtigt, denn sie zeigen, daß irgendwas an der Programmstruktur nicht der reinen Lehre entspricht.
Besser als dieses foo=0 ist es, die Programmstruktur zu ändern, bis eben das foo=0 nicht mehr nötig ist. I.d.R. läuft es eigentlich fast immer darauf hinaus, daß man nur eine Funktion in zwei zerlegen müßte.
"Never start optimizing before you have profiled it."
Die Zeiten, in denen man mit "smartem" C-Code auch zwangsläufig "ein paar Bytes sparen" konnte, sind mittlerweile vorbei. Sofern du dich nicht davon überzeugt hast, dass der generierte Code durch dein Zutun wirklich kleiner geworden ist, solltest du es einfach erstmal so leserlich wie möglich hinschreiben.
Beispiel aus der Praxis, gerade erst vor paar Tagen gehabt. Der Zählerwert eines 16-bit-Zählers soll so manipuliert werden, dass nach einer bestimmten Zeit ein Überlauf erfolgt. Das heißt, man muss das Komplement des gewünschten Timeouts da hineinladen. Komplement ist eine Negation, also sah der Code so aus:
... uint16_t timeout;
TCNT1 = (uint16_t)-timeout;
Funktioniert. Nun kam eine neue Version des IAR-Compilers (für den der Code auch da ist) daher und warnte darüber, dass hier ein unäres Minus auf eine vorzeichenlose Zahl angewendet wird. Hat er natürlich irgendwie Recht. Also hin und her gecastet:
TCNT1 = (uint16_t)(-((int16_t)timeout));
Sieht schrecklich aus, geht aber ohne Warnungen durch.
Aber Moment mal, was eigentlich gewollt war, war doch nur:
TCNT1 = 65536ul - timeout;
Das drückt eigentlich ziemlich genau das aus, was der Programmierer damit erreichen will: die Differenz zum Überlaufwert von 65536 soll ermittelt und da hinein geschrieben werden.
Was soll ich sagen: die letzte Formulierung erzeugt exakt den gleichen Code (trotz der formalen Berechnung als 32-bit-Datentyp), und sie läuft auch ohne Warnungen (sowohl GCC als auch IAR) durch.
Das ist das Holz, aus dem Sicherheitsbeauftragte geschnitzt werden. Fehlende volatile-Deklarationen führen im Problemfall typischerweise zu selten auftretenden nicht reproduzierbaren Fehlern und Abstürzen sowie nicht aufzuspürenden Heisenbugs.
Anekdotische Beweisführung ist in diesem Fall eine Riesendummheit. Selbst wenn auf dem aktuellen System 100% funktionieren, kann das mit der nächsten Compilerversion, dem nächsten Prozessor, einem weiteren Core, einer anderen Cacheline-size etc etc schon wieder vorbei sein, und dann ist es verdammt schwer rauszufinden, was eigentlich los ist.
Bezogen auf die Frage des OP nochmal eine kurze Darstellung, was der frei erhältliche GCC in Erscheinungsform des WinAVR aus den verschiedenen erdenklichen Formulierungen macht:
void hilo1(unsigned short adr) { union word_byte { struct { uint8_t lo; uint8_t hi; } byte; unsigned short word; } ad;
Variante hilo1 und hilo2 sind _nicht_ portabel, und die nichtportable Variante hilo2 erzeugt mit dem verzweifelten Versuch, es besser zu können als der Compiler, den schlechtesten Code.
Die einzigen für mich akzeptablen Formulierungen sind portable, also von den genannten hilo3 und hilo4, wobei bei hilo4 die gefahr besteht, dass ein 'dummer' Compiler plötzlich Divisionen in den Code einfügt.
Meine Empfehlung (wie auch schon im Posting von Christian Zietz genannt): Man verwende einfach nur '&' und '>>' (hilo3) und überlasse das Nachdenken über effiziente Codierung dem Compiler, der macht das schon.
ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here.
All logos and trade names are the property of their respective owners.