Zunächst sollten Sie wissen, dass in C die Standardtypen keine spezifische Genauigkeit (Anzahl der darstellbaren Werte) für die Standard-Integer-Typen haben. Es erfordert nur eine minimale Präzision für jeden Typ. Diese ergeben sich in den folgenden typischen Bit Größen, die standard ermöglichen komplexere Darstellungen:
char
: 8 Bit
short
: 16 Bit
int
: 16 (!) Bits
long
: 32 bits
long long
(ab C99): 64 Bits
Anmerkung: Die tatsächlichen Grenzen (die eine gewisse Präzision) eine Implementierung implizieren in limits.h
gegeben.
Zweitens wird der Typ einer Operation von den Typen der Operanden bestimmt, nicht vom Typ der linken Seite einer Zuweisung (weil Zuweisungen auch nur Ausdrücke sind). Dazu sind die oben angegebenen Typen nach Umrechnungsrang sortiert. Operanden mit kleinerem Rang als int
werden zuerst in int
konvertiert. Bei anderen Operanden wird der mit dem kleineren Rang in den Typ des anderen Operanden konvertiert. Dies sind die usual arithmetic conversions.
Ihre Implementierung scheint 16-Bit-unsigned int
mit der gleichen Größe wie unsigned short
zu verwenden, so a
und b
-unsigned int
umgewandelt wird, wird der Betrieb mit 16 Bit ausgeführt. Für unsigned
wird die Operation modulo 65536 (2 hoch 16) durchgeführt - dies wird Wrap-around genannt (dies ist nicht erforderlich für signierte Typen!). Das Ergebnis wird dann in unsigned long
konvertiert und den Variablen zugewiesen.
Für gcc nehme ich an, das kompiliert für einen PC oder eine 32-Bit-CPU. hierfür hat (unsigned) int
typischerweise 32 Bit, während (unsigned) long
mindestens 32 Bit (erforderlich) hat. Es gibt also keine Umgehung für die Operationen.
Hinweis: Für den PC werden die Operanden zu int
umgewandelt, nicht unsigned int
. Dies, weil int
bereits alle Werte von unsigned short
darstellen kann; unsigned int
ist nicht erforderlich. Dies kann zu einem unerwarteten (tatsächlich: Implementierung definierten) Verhalten führen, wenn das Ergebnis der Operation einen signed int
überläuft!
Wenn Sie Typen definierter Größe benötigen, siehe stdint.h
(seit C99) für uint16_t
, uint32_t
. Diese sind typedef
s zu Typen mit der entsprechenden Größe für Ihre Implementierung.
können Sie werfen auch einen der Operanden (nicht der ganze Ausdruck!) Auf die Art des Ergebnisses:
unsigned long c = (unsigned long)a + b;
oder Arten von bekannter Größe mit:
#include <stdint.h>
...
uint16_t a = 60000, b = 60000;
uint32_t c = (uint32_t)a + b;
Beachten Sie, dass Aufgrund der Konvertierungsregeln ist das Umwandeln eines Operanden ausreichend.
aktualisieren (dank @chux):
Die Besetzung oben arbeitet gezeigt ohne Probleme. Wenn a
jedoch einen höheren Konvertierungsrang als die Typumwandlung aufweist, wird der Wert möglicherweise auf den kleineren Typ reduziert.Während dies kann leicht als alle Typen zur Compile-Zeit (statische Typisierung) bekannt sind, vermieden werden, eine Alternative ist mit 1 der gewünschten Art zu multiplizieren:
unsigned long c = ((unsigned long)1U * a) + b
diese Weise wird der größere Rang der in dem gegebenen Cast oder a
(oder b
) wird verwendet. Die Multiplikation wird von jedem vernünftigen Compiler eliminiert.
Ein weiterer Ansatz, die Vermeidung auch die Zieltypnamen kennen, kann mit der typeof()
gcc Erweiterung erfolgen:
unsigned long c;
... many lines of code
c = ((typeof(c))1U * a) + b
Bezieht sich auf [Was passiert, wenn ein Integer-Überlauf in einem C-Ausdruck auftritt?] (Http://Stackoverflow.com/q/26195811/1708801) siehe auch [Warum muss ein Short vor arithmetischen Operationen in int konvertiert werden C und C++?] (Http://stackoverflow.com/q/24371868/1708801) –
Was ist 'Ihr Compiler'? Es sieht aus wie ein eingebetteter c-Compiler. Bessere Ansicht einer eingebetteten Toolchain speziell – HuStmpHrrr
Wenn Sie nicht einen eingebetteten Compiler verwenden, verwenden Sie wahrscheinlich Turbo C, die kein "echter" C-Compiler ist. Entfernen Sie es so schnell wie möglich –