2014-03-03 7 views
12

Lassen Sie das folgende Programm test.c berücksichtigen:Ganze Zahl ohne Vorzeichen Bitfeld Verschiebung Ausbeuten Ganzzahl mit Vorzeichen

#include <stdio.h> 

struct test { 
    unsigned int a:5; 
}; 

int main() { 
    unsigned int i; 
    struct test t = {1}; 
    for (i = 0; i < t.a << 1; i++) 
     printf("%u\n", i); 
    return 0; 
} 

Wenn kompilierten mit gcc -Wsign-compare test.c folgende Warnung erzeugt wird (getestet mit gcc 4.8.1):

test.c:9:19: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] 
    for (i = 0; i < t.a << 1; i++) 
       ^

clang -Wsign-compare test.c erzeugt das Folgende (getestet mit Klang 3.2):

test.c:9:19: warning: comparison of integers of different signs: 'unsigned int' and 'int' [-Wsign-compare] 
    for (i = 0; i < t.a << 1; i++) 
       ~^~~~~~~~~ 
1 warning generated. 

Somit wird der rechte Operand, ein verschobenes vorzeichenloses Bitfeld, zu einem vorzeichenbehafteten int. Diese Warnung zeigt für jedes Bit Feld Wert zwischen 1 und 31 enthalten. Bei höheren Werten wird keine Warnung ausgegeben. Das ist seltsam.

Dies wurde mit einem Bitfeld vom Typ unsigned short, unsigned int und unsigned long getestet. Letztere zeigen keine Warnung für Bitfeldwerte zwischen 32 und 64 an.

Wenn keine Verschiebung durchgeführt wird, gibt es keine Warnung, daher ist das Bitfeld wie erwartet nicht signiert.

Warum werden Bitfelder mit einer Größe kleiner als 32 Bit beim Verschieben signiert? Ich nehme an, dies ist kein Fehler, da dies sowohl mit gcc als auch mit clang übereinstimmt. Ich muss einige Informationen darüber verpassen, wie Bitfelder (oder Verschieben) funktionieren, aber was? Wie kann die Verschiebung eines vorzeichenlosen Werts einen vorzeichenbehafteten Wert ergeben?

Antwort

7

Integer Promotions auf die Operanden der Verschiebung der draft C99 standard Abschnitt behandelt angewendet werden 6.5.7bitweise Shift-Operatoren Absatz , die sagt (Hervorhebung von mir geht nach vorn):

Die Integer-Promotions durchgeführt werden, für jeden der Operanden

und die ganzzahlige Heraufstufung eines Bitfeldes abgedeckt ist in Abschnitt 6.3.1.1Boolean, Zeichen und Zahlen Absatz die sagt:

Folgendes kann in einem Ausdruck verwendet werden, wo ein int oder unsigned int verwendet werden können:

und enthält die folgende Kugel:

- Ein Bitfeld vom Typ _Bool, i nt, signed int oder unsigned int.

und sagt dann:

Wenn ein int alle Werte des ursprünglichen Typs darstellen kann, wird der Wert in einen int umgewandelt wird; Andernfalls wird es in einen unsigned int konvertiert. Diese werden die Ganzzahl Promotions genannt.48) Alle anderen Typen werden durch die ganzzahligen Aktionen nicht geändert.

es im draft C11 Standard geklärt wurde:

Wenn ein int alle Werte der Vorlagenart darstellen (wie durch die Breite beschränkt, für ein Bitfeld), ist der Wert, konvertiert zu einem int; Andernfalls wird es in einen unsigned int konvertiert. Diese werden als ganzzahlige Werbeaktionen bezeichnet. 58) Alle anderen Typen werden durch die Integer-Aktionen nicht geändert.

Also das ist das erwartete Verhalten.

+0

Und eine 31-Bit-Ganzzahl ohne Vorzeichen kann als int dargestellt werden und wird daher hochgestuft, aber ein 32-Bit-Vorzeichen ohne Vorzeichen kann nicht hochgestuft werden und bleibt unverändert. Ich wusste nichts von Beförderung. Vielen Dank. – bootleg

+2

@bootleg Wenn ein 32 Bit 'unsigned int' befördert werden kann oder nicht, hängt von der Breite von' unsigned int' ab. Unterschiedliche Ergebnisse für 32 und 64-Bit "unsigned". – chux

Verwandte Themen