www.mikrocontroller.net

Forum: Compiler & IDEs Frage an die C-Experten


Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich möchte gerne die Feldinhalte eines u08 Feldes (erg8) in das nieder- 
und höherwertige Byte einer u16 Variablen (abc) bringen und das Ganze 
möglichst ohne zeitaufwendige Bitschiebereien. Dabei habe ich mir 
folgende Lösung ausgetüftelt (Beispiel):

typedef unsigned char u08;
typedef unsigned short u16;

int main(void)
{
        u16 *ptr16,abc;
        u08 erg8[1];

        ptr16 = &abc;
        erg8[0] = 0x55;
        erg8[1] = 0xaa;
        *((u08 *)ptr16+1) = erg8[1];
        *(u08 *)ptr16 = erg8[0];
}
Jedenfalls meckert mein Compiler dabei nichts an und auch ein Test mit 
einem Debugger unter Linux (gcc) zeigt keine "Unsauberkeiten" und, last 
but not least, es läuft und bringt das erwartete Ergebnis. Trotzdem habe 
ich bei diesem Code irgendwie ein ungutes Gefühl. Kennt jemand für diese 
Problematik eine bessere oder schönere Lösung? Ist der Code oben korrekt 
oder fällt das schon unter die Rubrik "unsaubere Tricks"?

Vielen Dank!

Gruss,

Peter

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Bitschiebereien bei z.B. a=0xFF&(b>>8) werden von avr-gcc 
vollständig wegoptimiert.

Gruß
Andreas

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die Auskunft, aber irgenwie bleiben doch noch Fragen offen.

> Die Bitschiebereien bei z.B. a=0xFF&(b>>8) werden von avr-gcc vollständig 
wegoptimiert.

Naja, so vollständig wird er sie ja nicht wegoptimieren ;-)
Schliesslich soll er hier ja noch etwas tun.

Ist mein Code denn wenigstens ok und gibt es vielleicht noch andere 
Ideen?

Gruss,

Peter

Autor: Matthias Wulff (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vorschlag:

#include <io.h>
#include <progmem.h>
#include <stdlib.h>


typedef union conv CONV;
union conv{
  struct{
    unsigned char s_[2];
  }s;
  unsigned short d;
};

static CONV  conv_local;
static unsigned short ergebnis;

int main(void)
{

  conv_local.s.s_[0] = 0x55;
  conv_local.s.s_[1] = 0xaa;

  ergebnis = conv_local.d;



}

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du suchst eine Lösung für ein Problem das nicht existiert. AVR-GCC 
optimiert die Bitschiebereien NATÜRLICH vollständig weg, er liest im 
oben genannten Beispiel einfach den Inhalt der passenden Stelle im 
Speicher. Schau dir halt mal den erzeugten Assemblercode an.

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum machst Du es nicht mit UNION ?

union xyz
  {
  unsigned char Bytefeld[2];
  unsigned int  Integer;
  }

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Matthias & Sebastian,

danke für den Tip mit dem union!

Manchmal sieht man den Wald vor Bäumen nicht ;-)

Das ist die elegante Lösung, nach der ich gesucht habe! Man könnte sogar 
noch auf dem selben Speicherplatz ein Bitfeld anlegen und so elegant auf 
die einzelnen Bits (bitte ein Bit!) zugreifen. C ist ja doch eine tolle 
Programmiersprache, sofern man sie beherrscht. Aber das schaffe ich 
eines Tages auch noch.

Gruss,

Peter

Autor: Jonas Diemer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
was ist denn mit dieser variante:

int main(void)
{
u16 abc;
u08 erg8[1];

erg8[0] = 0x55;
erg8[1] = 0xaa;
abc = erg8[0] + (erg[1]<<8);
}

sollte doch zum selben ergebnis führen, oder?

Autor: Dirk Kramer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie sieht das eigentlich mit Felddeklarationen bei gcc aus?

 Im Ansi-C würde "u08 erg8[1];" nur ein Feld mit EINEM Eintrag (Index = 
0) erzeugen. Das ist doch mit gcc bestimmt nicht anders, oder?
Daraus würde dann folgen:

u08 erg8[2]; //mit Indizes 0 und 1

Falls einer eine gegesätzliche Auffassung hat, kann er das ja mal 
posten.

;-)

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Dirk

Ich habe mich in meinem Code oben vertan. Es muss natürlich ein Feld mit 
2 Elementen deklariert werden, also

u08 erg8[2];

Somit kann man auf erg8[0] und erg8[1] zugreifen. Übrigens ein Fehler, 
der in C gerne von Anfängern gemacht wird, womit ich mich hier mal 
wieder verraten habe ;-)

@Jonas

natürlich kann man das so auch schreiben. Ich fand es nur etwas 
unelegant, das ist alles.

Gruss,

Peter

Autor: Jonas Diemer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hmm, find ich persönlich eleganter, weil nur 1 zeile... aber is wohl 
geschmackssache. :-)

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wieso nur eine Zeile? Wenn ich z.B. ein union definiere, brauche ich 
überhaupt nichts mehr zu transferieren, also nach Deiner Rechnung wären 
das dann null Zeilen, sowas finde ich z.B. eleganter!

mit :-) Gruss

Peter

Autor: Jonas Diemer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hmm, da haste recht, das mit der union ist eleganter. ich hatte meins 
nur mit deinem ursprünglichen verglichen...

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich finde es übertrieben, für sowas extra eine union zu nehmen. Definier 
dir doch einfach ein Makro, z.B.
#define HIGH_BYTE(x) (0xFF&(x>>8))
Das macht den Code auch übersichtlicher.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Andreas
Du lässt einfach nicht locker ;-)

Dabei muss es, wenn schon mit Bitschieberei und Makro so heissen:

#define HIGH_BYTE(x) (0xFF&(x<<8))

Ok, ich frage ganz einfach meine Lebensgefährtin was ihr besser gefällt. 
Die hat zwar keine Ahnung von C, dafür weiss sie jedoch immer alles 
besser und hat letztendlich doch immer Recht ;-)

Gruss,

Peter

Autor: Schmittchen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Lebensgefährtin [...] hat letztendlich doch immer Recht ;-)
Na dann bist du wohl auch nicht erstaunt, daß sie Andreas' Lösung 
favorisiert, oder?!

(Es soll ja das Highbyte zurückgeliefert, und nicht eines generiert 
werden, oder?)

Ansonsten:
> #define HIGH_BYTE(x) (0xFF&(x<<8))
Bei deinem Ansatz wäre das Ergebnis immer 0. Besser:
#define HIGH_BYTE(x) (x<<8)

Schmittchen.

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
?
Das funktioniert doch beides nicht. (0xFF&(x>>8)) war schon richtig 
(wobei man sich das 0xFF& eigentlich sparen kann da bei >> Nuller 
nachgeschoben werden).

Gruß
Andreas

Autor: Schmittchen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Andreas: Auf was bezieht sich:
> Das funktioniert doch beides nicht.  ?

Ich war mir nicht sicher, was die Ursprungsfrage eigentlich war:
a.) Es soll das Highbyte zurückgegeben werden, dann gilt:
> Andreas' Lösung favorisiert
(also deine Lösung (Andreas) sollte stimmen)

oder b.) Es soll ein Highbyte generiert werden - um am Ende dann 
zusammen mit einem (Low)Byte ein 16Bit-Wert zu repräsentieren:
> #define HIGH_BYTE(x) (x<<8)
(setzt natürlich voraus, daß x als 16Bit-Variable deklariert ist... 
achso, eben hab ich dich verstanden: Wenn er es schon als 16Bit-Variable 
deklarieren muß, dann braucht die 2 8Bit-Variablen im Nachhinein nicht 
mehr zusammen zu tricksen.)

Aus Peters letzter Antwort war nicht eindeutig erkennbar, was er 
eigentlich will. In seinem ersten Posting klang das alles mehr nach 
generieren eines 16Bit-Wertes aus 2 8Bit-Werten.

Schmittchen, leicht verwirrt.

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stimmt, du hast recht, ich hatte gedacht er wollte es umgekehrt haben. 
Mein Fehler.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Andreas

Du hast Recht, die Bits müssen natürlich nach rechts geschoben werden. 
Und das Ausmaskieren kann man sich natürlich auch sparen. Also so sollte 
es dann richtig heissen:

#define HIGH_BYTE(x) (x>>8)

ok?

Sehrwahrscheinlich sind das noch so Erinnerungsfragmente, wo ich mal an 
little-Endian Systemen programmiert hatte. Ich glaube, da war das alles 
irgendwie anders herum.

Gruss,

Peter

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.