Forum: Compiler & IDEs 4x8Bit ins 1x32Bit


von fantomas (Gast)


Lesenswert?

Abend, gehts noch kürzer?
1
  #define BYTE4_TO_LONG(a,b,c,d)   (  (((((uint32_t)a) << 24)) & 0xFF000000)  + (((((uint32_t)b) << 16)) & 0x00FF0000)  + (((((uint32_t)c) << 8)) & 0x0000FF00)  + (((uint32_t)d) & 0x000000FF) )

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Man könnte noch über eine union arbeiten. Aber bei beiden Methoden: 
Achte auf das Thema Endianess und auf den Unterschied signed/unsigned...

von Matthias L. (Gast)


Lesenswert?

Die UND-Verknüpfungen kannst du dir sparen, da ein Byte sowieso nur max 
255 werden kann.....
1
#define BYTE4_TO_LONG(a,b,c,d)   (  ( ( (uint32_t)a) << 24))  + (  ( (uint32_t)b) << 16)  + ( ( (uint32_t)c) << 8)  + ( (uint32_t)d) )

von fantomas (Gast)


Lesenswert?

hab mal irgendwo gelesen das man aus Sicherheit unden soll. Stimmt es?

von Micha (Gast)


Lesenswert?

Was spricht gegen die Verwendung einer union?

von Matthias L. (Gast)


Lesenswert?

>hab mal irgendwo gelesen das man aus Sicherheit unden soll. Stimmt es?

Wenn du mir zeigst, das ein Byte größer als 0xFF sein kann, ja...


>Was spricht gegen die Verwendung einer union?

Nichts.

von tuppes (Gast)


Lesenswert?

> Was spricht gegen die Verwendung einer union?

Grundsätzlich nichts, würde ich sagen. Welche der Varianten zum 
kleinsten Code führt oder am wenigsten RAM verbraucht, ist vermutlich 
stark plattformabhängig.

Wenn man in dem Makro oben die VerUNDung weglässt, begibt man sich auf 
dünnes Eis, weil man dann unbemerkt auch Daten verwursten kann, die 
größer als 8 Bit sind. Das führt dann zu unerwarteten Ergebnissen.

Aus dem Grund würde ich sowas als Funktion schreiben, da ist die 
Typsicherheit besser:
1
unsigned long byte4_to_long (unsigned char a, b, c, d)
2
{
3
    return ((((((a << 8) | b) << 8) | c) << 8) | d);
4
}
Wer diese Funktion mit 16- oder 32-Bit-Argumenten füttert, bekommt 
entweder eine Compiler-Warnung ("data truncation") oder stillschweigend 
das richtige Ergebnis.

Aber auch hier gilt: Augen auf bei der Byte-Order.

von tuppes (Gast)


Lesenswert?

>>hab mal irgendwo gelesen das man aus Sicherheit unden soll. Stimmt es?

>Wenn du mir zeigst, das ein Byte größer als 0xFF sein kann, ja...

Wo steht, dass das Bytes sind?

von tuppes (Gast)


Lesenswert?

Halt! Fehler! Man muss die Daten vor dem Schieben auf 32 Bit bringen!
1
unsigned long byte4_to_long (unsigned char a, b, c, d)
2
{
3
    return (((((((unsigned long) a << 8) | b) << 8) | c) << 8) | d);
4
}

Sorry ...

von Skua (Gast)


Lesenswert?

>Wo steht, dass das Bytes sind?
Im Titel.


Aber findet der Typecast vor oder nach dem Speicherzugriff statt?
Ist das Normiert?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Matthias Lipinsky wrote:
>>hab mal irgendwo gelesen das man aus Sicherheit unden soll. Stimmt es?
>
> Wenn du mir zeigst, das ein Byte größer als 0xFF sein kann, ja...

Delault für char ist signed.
1
unsigned long foo (char c)
2
{
3
    return (unsigned long) c;
4
}
Wir demgemäß übersetzt zu
1
foo:
2
  mov r18,r24
3
  clr r19
4
  sbrc r18,7
5
  com r19
6
  mov r20,r19
7
  mov r21,r19
8
  movw r22,r18
9
  movw r24,r20
10
  ret

Zudem steht zu vermuten, daß der riesige Ausdruck, den BYTE4_TO_LONG 
erzeugt, nicht komplett auf der maschinenunabhängigen Ebene von gcc 
behandelt wird. Bzw es wird mit den 0xff-Masken einfacher (obwohl der 
Ausdruck komplexer ist) wenn man dem Compiler mit den Masken die Info 
gibt, daß es sich bei den 32-Byte werten nur um verschobene Bytes 
handelt. Er kann das zwar prinzipell wissen bzw. erkennen, aber irgendwo 
ist eben Ende, wie weit die Analyse getrieben wird.

Aus dem Grunde sollte man das Makro auf jeden Fall auch mit | schreiben 
anstsatt mit + ! Liefert hier zwar das gleiche, aber PLUS ist wesentlich 
fieser als OR, weil ersteres die Bits durcheinanderwürfelt.

>>Was spricht gegen die Verwendung einer union?
>
> Nichts.

Der Union ist klar der Vorzug zu geben, sowohl was Lesbarkeit der Quelle 
angeht, als auch was algebraische Darstellung im gcc angeht.

Johann

von Peter D. (peda)


Lesenswert?

Johann L. wrote:

>>>Was spricht gegen die Verwendung einer union?
>>
>> Nichts.

Ne Menge!

Wenn es um den Datenaustausch mit anderen Systemen geht, sollte man 
tunlichst auf ne Union verzichten, sonst krachts.
Und auch wenn der Code auf verschiedenen Compilern laufen soll.

Einige übliche Byteorders:

1, 2, 3, 4
2, 1, 4, 3
4, 3, 2, 1
3, 4, 1, 2


Peter

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter Dannegger wrote:
> Johann L. wrote:
>
>>>>Was spricht gegen die Verwendung einer union?
>>>
>>> Nichts.
>
> Ne Menge!
>
> Wenn es um den Datenaustausch mit anderen Systemen geht, sollte man
> tunlichst auf ne Union verzichten, sonst krachts.
> Und auch wenn der Code auf verschiedenen Compilern laufen soll.

Davon war nix geschrieben. Jemand, der nen TCP/IP Stck implementiert, 
ist sich glaub darüber im klaren, daß due Übertragung zwischen 
Plattformen unterschiedlicher Endianess geschehen kann.

Die Union funktioniert für little Endian. Für big Endian macht sie was 
anderes als das Makro -- auch ohne Kommunikation.

Johann

von tuppes (Gast)


Lesenswert?

>>Wo steht, dass das Bytes sind?
>Im Titel.
Ächz. Ich meinte: Wo in dem Makro ist das für den C-Compiler 
erkennbar?

Antwort: Gar nicht, d.h. er hat keine Chance, zu erkennen, wenn das 
Makro irrtümlich mit einem 16- oder 32-Bit-Wert aufgerufen wird.

> Aber findet der Typecast vor oder nach dem Speicherzugriff statt?
> Ist das Normiert?
Du meinst, ob das a 8- oder 32-bittig aus der Quelle (Stack?) geholt 
wird? Das kann der Compiler prinzipiell machen, wie er will, aber er 
muss es konsistent machen, also das Datum so vom Stack runterholen, wie 
es vor dem Function-Call draufgepusht wurde.

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.