Der Cast bildet also einen uint16_t* Datentyp aus einem 8-Bit-
Pointer.
Die Warnung lautet:
cast increases required alignment of target type
Kann das jemand genauer erklären? Braucht der Compiler ein Alignment
auf 32 Bit um pointern zu können? Ist das dann "Verschwendung" von
Speicherplatz? Fragen über Fragen ....
Frickelfritze schrieb:> Der GCC meldet unter Atmel Studio 7.0 bei folgendem Code eine Warnung.
Ach so ja, habe ich vergessen: Es handelt sich um ein SAM3X Kompilat.
Also ARM 32 bit .....
Frickelfritze schrieb:> Braucht der Compiler ein Alignment> auf 32 Bit um pointern zu können?
Nein, aber du hast einen Zeiger, der auf 8-Bit-Daten zeigt, der kann
also jedes Byte adressieren. Jetzt machst du einen draus, der
16-Bit-Daten adressieren können soll. Diese können aber nur auf
jeder geraden Adresse stehen. Wenn dein Zeiger vorher ganz legal auf
eine ungerade Adresse gezeigt hat, zeigt er jetzt auf etwas, auf dem
legal keine 16-Bit-Zahl stehen kann … Die Folge kann eine Pessimierung
der Zugriffe sein (Prozessor macht zwei Speicherzugriffe und baut sich
seine 16-Bit-Zahl daraus) oder auch ein misalignment trap / fault.
Schlechtes Design so.
Entweder popelst du dir deine 16-Bit-Zahl gleich aus den 8-Bit-Werten
zusammen in einer Zwischenvariable, oder du deklarierst den Zeiger
gleich auf passende Größe.
Wobei sich natürlich die generelle Frage stellt, warum du den
32-Bit-Prozessor mit einer Ladung an Maskierungsoperationen
beschäftigst,
damit der dir eine kastrierte 16-Bit-Prüfsumme ausrechnet. Deklarier'
doch den Zeiger als auf eine 32-Bit-Zahl zeigend und addiere dann
fortlaufend je vier Byte in der Prüfsumme. Das ist das, was der
Prozessor sowieso am schnellsten kann.
Wobei^2 sich natürlich die Frage stellt, wofür eine simple Prüfsumme
gut ist … CRC wäre besser.
Frickelfritze schrieb:> Kann ich dann dem Compiler helfen (Speicherzugriffe sparen) indem ich> meine(n) 8-bit Buffer immer auf 32 bit "aligne".
Ja, wenn du ihn 32bittig zugreifen willst, auf jeden Fall.
Aber wie schon geschrieben, wenn das wirklich 8-Bit-Daten sind,
dann nimm doch lieber eine CRC zur Prüfung. Die arbeitet auch mit
einzelnen Bytes, kann wahlweise 8, 16 oder 32 Bit als Ergebnis
liefern, und sie ist deutlich sicherer gegen Doppelbitfehler als
eine simple Prüfsumme.
Jörg W. schrieb:> damit der dir eine kastrierte 16-Bit-Prüfsumme ausrechnet. Deklarier'> doch den Zeiger als auf eine 32-Bit-Zahl zeigend und addiere dann> fortlaufend je vier Byte in der Prüfsumme. Das ist das, was der> Prozessor sowieso am schnellsten kann.
Das geht nicht da die vorgegebenen Datenstrukturen auf 16 Bit
Daten quantisiert sind, als z.B. 6 Byte lang sein können.
Leider ist die geerbte Software so gestaltet dass alles in
8-bit Buffern gehandled wird.
Jörg W. schrieb:> Wobei^2 sich natürlich die Frage stellt, wofür eine simple Prüfsumme> gut ist … CRC wäre besser.
Die Strukturen dazu sind gewachsen und können nicht verändert werden.
Siehe vorher ....
Frickelfritze schrieb:> Das geht nicht da die vorgegebenen Datenstrukturen auf 16 Bit> Daten quantisiert sind, als z.B. 6 Byte lang sein können.
Dann sollten sie auf jeden Fall auch auf 16-Bit-Grenzen ausgerichtet
werden.
Frickelfritze schrieb:> Leider ist die geerbte Software so gestaltet dass alles in> 8-bit Buffern gehandled wird.
Man muss auch auf 8-bit Elemente im Detail zugreifen können.
Frickelfritze schrieb:> Man muss auch auf 8-bit Elemente im Detail zugreifen können.
Zugriff auf 8-Bit-Elemente bei auf 16 Bit ausgerichteten Daten ist
nie ein Problem.
Jörg W. schrieb:> Frickelfritze schrieb:>> Kann ich dann dem Compiler helfen (Speicherzugriffe sparen) indem ich>> meine(n) 8-bit Buffer immer auf 32 bit "aligne".>> Ja, wenn du ihn 32bittig zugreifen willst, auf jeden Fall.
Nach einiger Überlegung .....
... bewirkt der Cast von 8 auf 16 Bit aber dass der Compiler auf
jeden Fall den Einzelzugriff mit 2 mal 8 bit generieren wird da
er ja nicht von vorne herein weiss ob die Adresse die der Funktion
übergeben worden ist, entsprechend aligned ist oder nicht.
Somit hilft das vorgreifende alignen eines Buffers nichts um den
Zugriff zu optimieren bzw zu beschleunigen.
Gegenargumente?
Frickelfritze schrieb:> Nach einiger Überlegung .....> ... bewirkt der Cast von 8 auf 16 Bit aber dass der Compiler auf> jeden Fall den Einzelzugriff mit 2 mal 8 bit generieren wird da> er ja nicht von vorne herein weiss ob die Adresse die der Funktion> übergeben worden ist, entsprechend aligned ist oder nicht.
Nö. Er hat dich ja gewarnt, dass er jetzt 16-Bit-Zugriffe macht.
Was dein Prozessor dann daraus macht, ist eine Konfigurationsfrage.
Entweder ein Trap (usage fault) oder ein langsamer Zugriff.
Frickelfritze schrieb:> Nach einiger Überlegung .....> ... bewirkt der Cast von 8 auf 16 Bit aber dass der Compiler auf> jeden Fall den Einzelzugriff mit 2 mal 8 bit generieren wird da> er ja nicht von vorne herein weiss ob die Adresse die der Funktion> übergeben worden ist, entsprechend aligned ist oder nicht.>> Somit hilft das vorgreifende alignen eines Buffers nichts um den> Zugriff zu optimieren bzw zu beschleunigen.>> Gegenargumente?
Wenn deine Buffer aligned sind wird der Zugriff schneller. Der
Cortex-M3 löst das unaligned Problem transparent im Hintergrund
und splittet einen 16Bit Zugriff auf 2 8Bit Zugriffe auf dem Bus.
Trap schrieb:> Der Cortex-M3 löst das unaligned Problem transparent im Hintergrund
Optional. Man kann den Core auch so konfigurieren, dass er einen
Usage Fault wirft, indem man das UNALIGN_TRP im SCB_CCR setzt.
Zumindest für die Entwicklung (Debugging und Stresstest) ist das
eigentlich eine gute Idee, das immer zu setzen.
Trap schrieb:> Wenn deine Buffer aligned sind wird der Zugriff schneller. Der> Cortex-M3 löst das unaligned Problem transparent im Hintergrund> und splittet einen 16Bit Zugriff auf 2 8Bit Zugriffe auf dem Bus.
Tolle Sache wenn der Prozessor das "at runtime" unterscheiden kann.
Hätte ich ihm jetzt nicht zugetraut.
Wofür aber ist dann so ein "Usage Fault" wenn er die Zugriffe
sowieso meistern kann und kein Fehler für den User zustande kommt?
Frickelfritze schrieb:> Wofür aber ist dann so ein "Usage Fault" wenn er die Zugriffe> sowieso meistern kann und kein Fehler für den User zustande kommt?
Weil es eben ein nicht optimaler Zugriff ist. Normalweise möchte man
doch Code haben, der so schnell wie möglich abläuft, und das setzt
sauber ausgerichtete Zugriffe auf den Speicher voraus.
>> Gibt es einen Grund, aufwändig die Zeiger-Dereferenzierung zu klammern,> wenn man es auch als Array-Zugriff schreiben kann?
Keine wirklich akzeptablen Grund. Die Klammern standen halt schon da und
ich war zu faul, diese Zeile auch noch umzustellen. :-)
Klaus schrieb:> Warum so kompliziert von hinten durchs Auge?
Weil mancher Debugger keine Ausdrücke berechnen kann und
man beim Debuggen dann blind ist. Zwischenergebnisse sind
da immer nützlich.
Dann lieber straight forward und hausbacken ....
Es kommt in dieser Funktion auch nicht auf Geschwindigkeit
an. Mich interessierte nur die seltsame Warnung.
Danke für die Erklärungen.
Frickelfritze schrieb:> Klaus schrieb:>> Warum so kompliziert von hinten durchs Auge?>> Weil mancher Debugger keine Ausdrücke berechnen kann und> man beim Debuggen dann blind ist. Zwischenergebnisse sind> da immer nützlich.>
Die sind ja durchaus erkennbar. Guck Dir einfach die Checksumme an. Und
falls Du es explizit haben willst, dann:
> Dann lieber straight forward und hausbacken ....
Tut mir leid, aber dein Code ist eben nicht "straight forward" und schon
gar nicht hausbacken. Schon das alignment Problem ist ein Zeichen dafür.
Auf der ideellen Maschine (im Standard steht, glaube ich, ein anderer
Begriff aber ich bin immer noch zu faul) gibt es sowas nämlich nicht.
Und wenn der Compiler warnen muss, dann ist das ein Zeichen, dass die
Entfernung zwischen der Anwendung der ideellen und der realen Maschine
merklich ist.
Verstehe mich recht. Mache es wie Du willst, aber Deine Begründung ist,
meiner Ansicht nach, sachlich nicht zutreffend.
> Es kommt in dieser Funktion auch nicht auf Geschwindigkeit> an.
Mit Geschwindigkeit hat das nichts zu tun. Es mag evtl. einen
Unterschied zwischen den Codevarianten geben, aber ich vermute, er ist
nicht wesentlich.
> Mich interessierte nur die seltsame Warnung.> Danke für die Erklärungen.
Gerne.
Jörg W. schrieb:> Trap schrieb:>> Der Cortex-M3 löst das unaligned Problem transparent im Hintergrund>> Optional. Man kann den Core auch so konfigurieren, dass er einen> Usage Fault wirft, indem man das UNALIGN_TRP im SCB_CCR setzt.> Zumindest für die Entwicklung (Debugging und Stresstest) ist das> eigentlich eine gute Idee, das immer zu setzen.
Atmel SAM3X:
Unaligned LDM, STM, LDRD, and STRD instructions always fault
irrespective of whether UNALIGN_TRP is set to 1.
Will man unaligned Zugriffe ausnutzen, muss man die Benutzung dieser
Befehle abschalten. Weiß nicht, ob dies beim gcc möglich ist.
Sollte aber gehen, sobald man den Pointer auf __packed deklariert. Dann
werden jedoch explizit 8bit Befehle genutzt und aufwendig
zusammengesetzt.
Nur mal als weiterer Denkanstoß. Die vorgenannten Infos beziehen sich ja
auf notwendige Randbedingungen für eine höhere Effektivität. Da aber
eine gewachsene Software im Gespräch war, ist dies möglicherweise nicht
realisierbar.
Jörg W. schrieb:> Gibt es einen Grund, aufwändig die Zeiger-Dereferenzierung zu klammern,> wenn man es auch als Array-Zugriff schreiben kann?
Ja, MISRA. MISRA mag keine Pointer indizieren.
Eric B. schrieb:> MISRA mag keine Pointer indizieren.
Manche Sachen an MISRA muss man wohl nicht verstehen.
Wenn ich ein Array an eine Funktion übergebe, wird bekanntlich ein
Zeiger übergeben. Den darf ich dann in der aufgerufenen Funktion
aber nicht mehr wie ein Array behandeln.
Naja, es gibt Sachen an MISRA, die sinnvoll sind, aber manche der
Begründungen, die ich da gelesen habe, erscheinen eher an den Haaren
herbeigezogen.
Wenn auch halb scherzhaft, so meine ich, das Argumente, die sich auf
MISRA berufen (so MISRA nicht selbst das Thema ist) hier vermieden
werden sollte.
Das ist die P... im A... Die Stein gewordene Sorgenfalte irgendeines
Buchhalters. Scheisslich.