mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Shift-Operation im Makro mit UND


Autor: Shift (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich sehe hier in einem Programm folgende eine Konstruktion, warum macht 
man das so?


#define MAKRO 3
#define NEUESMAKRO ((MAKRO<<8) & 0xFF00)


Wo ist der Unterschied zu

#define NOCHEINNEUESMAKRO (MAKRO<<8)


Was gewinnt man durch die UND-Operation an dieser Stelle?
Sinn scheint ja wohl zu sein, dass das untere Byte definitiv auf Null 
steht. In welcher Situation könnte es denn passieren, dass nach dem 
Shift hier keine Null im niederen Byte steht?

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Shift schrieb:
> In welcher Situation könnte es denn passieren, dass nach dem
> Shift hier keine Null im niederen Byte steht?

Ich kenne keine. Meines Wissens werden beim Left-Shift immer 0en 
reingeschoben. Anders ist es beim Right-Shift im Zusammenhang mit 
vorzeichenbehafteten Variablen.

Autor: Clemens L. (c_l)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Shift schrieb:
> Was gewinnt man durch die UND-Operation an dieser Stelle?

Gar nichts.

Es wäre möglich, dass diese Makros automatisch generiert wurden.

Oder dass es andere Makros gibt, wo das UND notwendig ist, und es hier 
aus Konsistenzgründen beibehalten wurde.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde mal sagen, das "& 0xFF00" löscht der Optimizer einfach, d.h. 
der erzeugte Code ist der gleiche.

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Allerdings habe ich auf Wikipedia folgende interessante Bemerkung 
gefunden:

---------
Ebenso ist das Ergebnis laut C- und C++-Sprachnorm undefiniert, wenn die 
Anzahl der Bitverschiebungen größer oder gleich der Bitbreite der 
Rechenarchitektur ist.[2] Wird beispielsweise auf einer 
32-Bit-Architektur von Intel-Prozessoren gearbeitet (IA32), so bewirkt 
eine Verschiebung um 32 Stellen oft gar keine Veränderung des 
Ergebnisses, d. h. für x = y << 32 ergibt sich x == y. Der Grund liegt 
in der Art und Weise, wie die Compiler die Schiebeoperation in 
Maschinencode umsetzen.
---------

Und tatsächlich:
#include <stdio.h>
#include <stdint.h>

int main()
{
    uint32_t x = 0xFFFFFFFF;

    printf ("%u\n", x);

    x <<= 32;

    printf ("%u\n", x);
}

$ cc t.c && ./a.out
t.c: In function 'main':
t.c:10:5: warning: left shift count >= width of type
     x <<= 32;
     ^
4294967295
4294967295

Hier passiert tatsächlich - bis auf die Warnung - ... nichts!

Ersetze ich uint32_t durch uint8_t, initialisiere ich x mit 0xFF und 
schiebe nur um 8 Stellen, kommt aber tatsächlich nach dem Schieben 
wieder 0 raus.

Fazit: Das vom TO angegebene Makro könnte höchstens relevant sein auf 
Büchsen, bei denen uint8_t identisch mit unsigned int ist. Aber da 
bringt das Schieben um 8 Stellen sowieso nichts.

: Bearbeitet durch Moderator
Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Frank M. (ukw) Benutzerseite

>Ebenso ist das Ergebnis laut C- und C++-Sprachnorm undefiniert, wenn die
>Anzahl der Bitverschiebungen größer oder gleich der Bitbreite der
>Rechenarchitektur ist.[2] Wird beispielsweise auf einer
>32-Bit-Architektur von Intel-Prozessoren gearbeitet (IA32), so bewirkt
>eine Verschiebung um 32 Stellen oft gar keine Veränderung des
>Ergebnisses, d. h. für x = y << 32 ergibt sich x == y. Der Grund liegt
>in der Art und Weise, wie die Compiler die Schiebeoperation in
>Maschinencode umsetzen.
>---------

Das halte ich für ein Gerücht. Sowohl was die Rechenarchitektur als auch 
das Verhalten bei IA32 angeht.

Auch der AVR kann 32, ja sogar 64 Bit Variablöen verarbeiten, und das 
macht er auch korrekt! Eher ist so, das ein (konstantes) Lichtsschieben 
um mehr Bits als die Variable umfasst immer 0 ergibt, ggf. sogar 
optimiert ohne echtes Schieben. Der Compiler mag eine Warnung ausgeben, 
aber er MUSS die Schiebeoperation ausführen!

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Falk B. schrieb:
> Der Compiler mag eine Warnung ausgeben,
> aber er MUSS die Schiebeoperation ausführen!

Du meinst also, gcc hat hier einen Bug?

Ich glaube sogar, dass gcc die Schiebeoperation durchführt, aber der 
Prozessor nicht. ;-)

Nochmal die Ausgabe:
$ cc t.c && ./a.out
t.c: In function 'main':
t.c:10:5: warning: left shift count >= width of type
     x <<= 32;

Der Compiler meckert also genau den Fall an, der bei Wikipedia erwähnt 
ist.

Output:
4294967295
4294967295

0xFFFFFFFF um 32 Stellen nach links geschoben ergibt also 0xFFFFFFFF.
# gcc --version
gcc (Debian 4.9.2-10) 4.9.2
# cat /proc/cpuinfo | grep model
...
model name      : Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz

: Bearbeitet durch Moderator
Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Frank M. (ukw) Benutzerseite

>> Der Compiler mag eine Warnung ausgeben,
>> aber er MUSS die Schiebeoperation ausführen!

>Du meinst also, gcc hat hier einen Bug?

Keine Ahnung, aber es würde mich schon arg wundern, wenn DAS ein 
normgerechtes Verhalten von C wäre. Wobei, es ist ja C . . . . 8-0

>Ich glaube sogar, dass gcc die Schiebeoperation durchführt, aber der
>Prozessor nicht. ;-)

Ein 2. FDIV Bug? ;-)

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Falk B. schrieb:
> Ein 2. FDIV Bug? ;-)

Wohl eher ein Feature ;-)

Zitat von:

The C programming language:

The result is undefined if the right operand is negative, or greater 
than or equal to the number of bits in the left expression’s type.

Zitat von

IA-32 Intel Architecture Software Developer’s Manual 3

The 8086 does not mask the shift count. However, all other IA-32 
processors (starting with the Intel 286 processor) do mask the shift 
count to 5 bits, resulting in a maximum count of 31. This masking is 
done in all operating modes (including the virtual-8086 mode) to reduce 
the maximum execution time of the instructions.

-----
Der Compiler muss also gar nichts bei Left-Shifts >= 32 (im Fall von 
uint32_t).

EDIT:

Sowohl auf einer Linux-Büchse mit ELF 32-bit als auch als ELF 64-bit 
Executable ist das Verhalten identisch.
# file a.out
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped

: Bearbeitet durch Moderator
Autor: Falk Brunner (falk)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Also mal wieder so ein "tolles" Feature von C, ich hab's geahnt.

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Falk B. schrieb:
> Also mal wieder so ein "tolles" Feature von C, ich hab's geahnt.

Aber so gut wie nicht relevant. Ich glaube nicht, dass wir beide jemals 
auf die Idee kommen werden, einen 32-Bit-Wert um 32 Bit oder mehr zu 
shiften. Das hört sich doch schon so ziemlich sinnlos an.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Frank M. (ukw) Benutzerseite

>Aber so gut wie nicht relevant. Ich glaube nicht, dass wir beide jemals
>auf die Idee kommen werden, einen 32-Bit-Wert um 32 Bit oder mehr zu
>shiften. Das hört sich doch schon so ziemlich sinnlos an.

Als konstante Verschiebung eher nicht, aber als variable Verschiebung 
ist das durchaus denkbar. In dem Fall kann man nur hoffen, daß die 
variable Verschiebung als Mehrfachverschiebung umgesetzt wird und somit 
zum erwarteten Ergebnis führt. Schön ist das aber nicht.

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Falk B. schrieb:
> Als konstante Verschiebung eher nicht, aber als variable Verschiebung
> ist das durchaus denkbar.

Ja, zum Beispiel in einer Schleife das Verschieben um eins.

Oder (ungünstig ohne Barrel-Shifter) das Verschieben mit:
for (i = 0; i < sizeof (uint32_t); i++)
{
    if (irgendwas & (1<<i))
    {
       setze_bit_auf_1();
    }
    else
    {
       setze_bit_auf_0();
    }
}

Aber auch da läuft das i nur bis 31 und nicht 32. Von daher keine 
Gefahr. Wenn ich tatsächlich einen Wert von 32 Bit um mehr als 31 Bit 
variabel verschiebe, dann betrachte ich das als Bug in meinem Programm 
- nicht als Bug im Compiler.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Frank M. (ukw) Benutzerseite

>Ja, zum Beispiel in einer Schleife das Verschieben um eins.

>Oder (ungünstig ohne Barrel-Shifter) das Verschieben mit:

>for (i = 0; i < sizeof (uint32_t); i++)

Da fehlt wohl ein *8, denn die Schleife ist nach 4 Durchläufen beendet.

{
>    if (irgendwas & (1<<i))

Ich bin ein Fan von Bitmasken, vor allem auf dem AVR. Ist deutlich 
schneller.

>Aber auch da läuft das i nur bis 31 und nicht 32. Von daher keine
>Gefahr. Wenn ich tatsächlich einen Wert von 32 Bit um mehr als 31 Bit
>variabel verschiebe, dann betrachte ich das als Bug in meinem Programm
>- nicht als Bug im Compiler.

Hmm, auch ein Blickwinkel 8-0

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Falk B. schrieb:

> Da fehlt wohl ein *8, denn die Schleife ist nach 4 Durchläufen beendet.

Stümmt :-)

Autor: Jim Meba (turboj)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Shift schrieb:
> #define MAKRO 3
> #define NEUESMAKRO ((MAKRO<<8) & 0xFF00)
>
> Wo ist der Unterschied zu
>
> #define NOCHEINNEUESMAKRO (MAKRO<<8)

Das Ergebnis wird auf die 16 Bits geclippt, wenn MAKRO mal größer als 
255 ist. Bei 32 Bit Registern wäre das dann nicht mehr egal. Das macht 
man oft wenn die höherwertigen Bits eine andere Funktion haben.

Und ja, im Beispiel überflüssig und spätestens vom Optimizer entfernt.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frank M. schrieb:
> Fazit: Das vom TO angegebene Makro könnte höchstens relevant sein auf
> Büchsen, bei denen uint8_t identisch mit unsigned int ist.

Weniger als 16 Bits für int/unsigned sind nicht zum C Standard konform.

: Bearbeitet durch User
Autor: Paul Baumann (paul_baumann)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frank M. schrieb:
> Ich glaube nicht, dass wir beide jemals
> auf die Idee kommen werden, einen 32-Bit-Wert um 32 Bit oder mehr zu
> shiften.

Man soll ja Nichts auf die lange Bank schieben.
:)
MfG Paul

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.