lange lange vs int Multiplikation
Angesichts der folgenden snippet:
#include <stdio.h>
typedef signed long long int64;
typedef signed int int32;
typedef signed char int8;
int main()
{
printf("%i\n", sizeof(int8));
printf("%i\n", sizeof(int32));
printf("%i\n", sizeof(int64));
int8 a = 100;
int8 b = 100;
int32 c = a * b;
printf("%i\n", c);
int32 d = 1000000000;
int32 e = 1000000000;
int64 f = d * e;
printf("%I64d\n", f);
}
Die Ausgabe mit MinGW-GCC 3.4.5 ist (-O0):
1
4
8
10000
-1486618624
Den ersten Multiplikation ist eingegossen in einen int32-intern (nach der assembler-Ausgabe). Die zweite Multiplikation wird nicht gegossen. Ich bin mir nicht sicher, ob die Ergebnisse abweichen, weil das Programm lief auf einem IA32 oder weil es irgendwo definiert, die in C-standard. Dennoch bin ich daran interessiert, wenn genau dieses Verhalten ist irgendwo definiert (ISO/IEC 9899?), weil ich gerne besser verstehen, warum und wenn ich casten manuell (ich habe Probleme die Portierung eines Programms von einer anderen Architektur).
Du musst angemeldet sein, um einen Kommentar abzugeben.
Den C99-standard nicht angeben, dass binäre Operatoren, wie
*
arbeiten nicht auf integer-Typen, die kleiner alsint
. Ausdrücke dieser Arten werden gefördert, zumint
bevor der operator angewendet wird. Siehe 6.3.1.4 Absatz 2 und die zahlreichen vorkommen der Wörter "integer promotion". Dies ist aber etwas orthogonal zur Montage-Anweisungen vom compiler generiert, die sich aufint
s, denn dieser ist sogar schneller, wenn der compiler erlaubt sein würde, berechnet eine kürzere Folge (denn das Ergebnis ist sofort gespeichert in einem l-Wert von kurzer Typ, zum Beispiel).Bezüglich
int64 f = d * e;
wod
unde
Typint
die Vermehrung erfolgt alsint
im Einklang mit der gleichen Aktion-Regeln. Der überlauf ist technisch Undefiniertes Verhalten, Sie bekommen zwei s-Komplement Ergebnis hier, aber Sie konnte sich nichts nach der Norm.Hinweis: die promotion-Regeln unterscheiden signed-und unsigned-Typen bei der Förderung. Die Regel ist die Förderung der kleineren Arten zu
int
es sei dennint
kann nicht repräsentieren alle Werte des Typs, in dem Fallunsigned int
verwendet wird.Das problem ist, dass die Multiplikation ist int32 * int32, was getan wird, als int32, und das Ergebnis dann zugewiesen werden, um ein int64. Sie würden viel die gleiche Wirkung mit
double d = 3 /2;
, die würden teilen 3 von 2 unter Verwendung der integer-division und zuweisen von 1,0 bisd
.Müssen Sie pay Aufmerksamkeit auf die Art von Ausdruck oder Teilausdruck, Wann immer es kann von Bedeutung sein. Dies erfordert, machen Sie sicher, dass die entsprechende operation wird berechnet als die entsprechenden Typ, wie Gießen eine der multiplicands zu int64, oder (in meinem Beispiel)
3.0 /2
oder(float)3 /2
.int64 f = (int64)d * e;
int
wenn Sie waren von kleineren Arten. Ein Blick auf die C99-standard schlägt vor, dass dies nicht mehr der Fall, aber ich bin mir nicht wirklich sicher. Welchen C-compiler benutzt du, und, wenn anwendbar, mit welchen Optionen?Lesen K&R (das original). Alle integer-Operationen fertig sind mit dem natürlichen Typ integer, es sei denn, es beinhaltet die Variablen, die sind (oder gegossen) etwas größer. Die Operationen auf char sind gegossen, die auf 32 bit, weil das die Natürliche Größe von integer auf, die Architektur. Die Multiplikation von zwei 32-bit-Ganzzahlen erfolgt in 32 bit, weil nichts ist, Gießen Sie es etwas größer (bis Sie auf zuweisen, um die 64-bit-variable, aber das ist zu spät). Wenn Sie möchten, dass der Betrieb geschehen in 64 bit umwandeln einer oder beide int-Werte zu 64 bit.
a * b
wird berechnet als ein int, und dann gegossen, um den Empfang variable Typ (der zufälligerweise int)d * e
wird berechnet als ein int, und dann gegossen, um den Empfang variable geben (was nur passiert int64)Wenn entweder der Typ Variablen wurden größer, dass ein int (oder waren Gleitkommazahl), als die Art verwendet worden wären. Aber da alle verwendeten Typen in die multipliziert wurden, int oder kleiner, ints verwendet wurden.