2013-08-16 19 views
8

mam:konwersja int na krótki w C

int a = 2147483647; 
short b = (short)a; 

i dostaję b = -1 natomiast spodziewam int32 być konwertowane do int16 (short). Spodziewam się zobaczyć pewną wartość i nie-1.

Proszę, pomóż mi z tym.

+1

Powiedziałbym, że wartość nie pasuje, więc wyniki są niezdefiniowane. –

+2

'-1' * to *" pewna wartość ". I "obsada" (krótka) jest niepotrzebna; konwersja zostanie wykonana niejawnie: 'short b = a;' –

+2

@BartFriederichs: Wynik konwersji jest * zdefiniowany przez implementację *, a nie niezdefiniowany. –

Odpowiedz

3

Twój int A jest większy niż rozmiar krótki. Kiedy konwertujesz A na krótki, otrzymasz 1 w lewym górnym rogu, co oznacza, że ​​jest liczbą ujemną. Ponieważ masz -1, przypuszczam, że otrzymujesz 1 na 16 bitach, co da ci -2^15 + 2^14 + 2^13 ... + 2^0, co da ci -1. W skrócie (gra słów nie jest przeznaczona), nie można przekształcić liczby całkowitej na krótką, jeśli jest zbyt duża.

17

Wartość 2147483647 lub 2 -1 powoduje przepełnienie 16-bitowej liczby całkowitej. Jego binarna reprezentacja wynosi zero w MSB, a następnie 31 w pozostałych bitach.

Wygląda na to, że w twojej implementacji zostało 16 ostatnich bitów w konwersji na short. Kiedy to nastąpi, wszystkie z nich są ustawione na 1, w wyniku 2's complement reprezentacji -1:

32-bit int: 01111111111111111111111111111111 
16-bit short: ----------------1111111111111111 

Jednak ani reprezentacji 2-komplement ani zachowanie to w ogóle jest częścią ++ standard C, więc to zachowanie jest zdefiniowany przez implementację.

+7

@EricPostpischil: Zachowanie nie jest niezdefiniowane; wynik jest definiowany przez implementację, co oznacza, że ​​implementacja musi to dokumentować. –

+2

@EricPostpischil: n3690 strona 80 4.7 (1) mówi, że jest to definicja zdefiniowana, a nie nieokreślona. Nie jestem pewien, czy implementacja jest wolna, aby zdefiniować niezdefiniowane zachowanie, jednak :-) – 6502

6

to implementation defined zachowanie, na przykład gccIntegers Implementation document mówi:

Do konwersji do rodzaju szerokości N, przy czym zmniejsza się wartość modulo 2^N, aby znajdować się w zasięgu typu; brak sygnału.

To może się różnić od kompilatora do kompilatora, nie jestem w stanie wykopać podobnych dokumentów dla clang ani visual studio.

Od projektu C++ standard, sekcja 4.7 Integral conversions ustęp 3:

Jeśli typ docelowy jest podpisany, wartość pozostaje niezmieniona, jeżeli może być przedstawiony w rodzaju przeznaczenia (i nieco pola szerokości); w przeciwnym razie wartość jest zdefiniowana w ramach implementacji.

Jeśli to był unsigned wtedy byłby doskonale zdefiniowane zachowanie, zgodnie z pkt 2:

Jeśli typ docelowy jest niepodpisany, otrzymaną wartość jest co najmniej liczba całkowita bez znaku przystające do całkowitej źródłowym (modulo 2n gdzie n jest liczbą bitów używanych do reprezentowania typu bez znaku). [Uwaga: W przedstawieniu uzupełnienia dwójkowego, konwersja jest konceptualna i nie ma zmiany w wzorze bitowym (jeśli nie ma skracania).-end note]

Język jest podobny w C99 wstępnym odcinku standardowym 6.3.1.3 Signed and unsigned integers.

9

Konwersja wartości do podpisany typu, gdy wartość źródło nie pasuje typu docelowego uzyskując realizacji zdefiniowanej wynik. Oznacza to, że każda zgodna dokumentacja kompilatora musi dokumentować, jaki jest ten wynik.

(Jest to w przeciwieństwie do zachowania na przepełnienie operatora arytmetycznego. Na przykład:

int overflow = INT_MAX + 1; 

faktycznie ma niezdefiniowanej zachowanie Ale w każdym przypadku, należy uważać, aby napisać kod tak nie robi. Wyzwalanie tego rodzaju problemów.)

Dla wielu implementacji, zarówno dla konwersji, jak i arytmetycznych, przepełnienie, w którym cel jest typem N-bitowym, po prostu przyjmuje N-rzędne bitów niskiego rzędu z prawidłowego wyniku.

W twoim przypadku najwyraźniej int ma 32 bity, a short ma 16 bitów (te rozmiary mogą się różnić w zależności od implementacji). 2147483647 to 0x7fffffff, 16-bitowe bity niskiego rzędu to 0xffff, który jest (ponownie, na twojej implementacji) reprezentacją -1 w typie short.

W przypadku konwersji na typy bez znaku wynik jest ściśle określony przez standard; pobiera n-bitowe N bitów wyniku. I dla przepełnienia konwersji zmiennoprzecinkowej (powiedzmy, konwersji bardzo dużej wartości double na float), zachowanie jest niezdefiniowane.

Jak dotąd, to samo dotyczy C i C++. Ale aby dodać do zamieszania, począwszy od standardu z 1999 r. Przepełniona podpisana konwersja może podnieść sygnał zdefiniowany w ramach implementacji. C++ tego nie ma. Nie znam żadnego kompilatora, który faktycznie to robi.

spodziewam się zobaczyć jakąś wartość i nie-1.

-1jest "jakaś wartość". Czy była jakaś konkretna wartość, której się spodziewałeś?

Nawiasem mówiąc:

short b = (short)a; 

W obsadzie jest niepotrzebna. Przypisanie, inicjalizacja, przekazywanie parametrów i instrukcje return mogą przypisać wartości między dowolnymi typami liczbowymi bez rzutowania. Wartość jest konwertowana niejawnie:

short b = a; 
3

Można to zrobić:

uint32_t sum=0xFFFF1234; 
uint16_t *p= (uint16_t *) ∑ 
uint16_t checksum=p[0]; 

check-suma jest 0x1234.

Oto kolejny sposób:

union ToShort 
{ 
     uint32_t sum; 
     uint16_t checksum[2]; 
} toShort; 
toShort.sum=0xFFFF1234; 
cout << hex << toShort.checksum[0]; 

wyjście jest 1234.