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?
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.
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.
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:
1
#include <stdio.h>
2
#include <stdint.h>
3
4
intmain()
5
{
6
uint32_tx=0xFFFFFFFF;
7
8
printf("%u\n",x);
9
10
x<<=32;
11
12
printf("%u\n",x);
13
}
$ 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.
@ 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!
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:
1
$ cc t.c && ./a.out
2
t.c: In function 'main':
3
t.c:10:5: warning: left shift count >= width of type
4
x <<= 32;
Der Compiler meckert also genau den Fall an, der bei Wikipedia erwähnt
ist.
Output:
1
4294967295
2
4294967295
0xFFFFFFFF um 32 Stellen nach links geschoben ergibt also 0xFFFFFFFF.
@ 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? ;-)
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.
1
# file a.out
2
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
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.
@ 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.
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:
1
for(i=0;i<sizeof(uint32_t);i++)
2
{
3
if(irgendwas&(1<<i))
4
{
5
setze_bit_auf_1();
6
}
7
else
8
{
9
setze_bit_auf_0();
10
}
11
}
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.
@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
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.
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.
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
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