Forum: Compiler & IDEs Frage an die C-Experten


von Peter (Gast)


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

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

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

Gruß
Andreas

von Peter (Gast)


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

von Matthias Wulff (Gast)


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;



}

von Andreas S. (andreas) (Admin) Benutzerseite


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.

von Sebastian (Gast)


Lesenswert?

Warum machst Du es nicht mit UNION ?

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

von Peter (Gast)


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

von Jonas Diemer (Gast)


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?

von Dirk Kramer (Gast)


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.

;-)

von Peter (Gast)


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

von Jonas Diemer (Gast)


Lesenswert?

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

von Peter (Gast)


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

von Jonas Diemer (Gast)


Lesenswert?

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

von Andreas S. (andreas) (Admin) Benutzerseite


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.

von Peter (Gast)


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

von Schmittchen (Gast)


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.

von Andreas S. (andreas) (Admin) Benutzerseite


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

von Schmittchen (Gast)


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.

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

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

von Peter (Gast)


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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.