Dziwne zachowanie rzutowania

Odpowiedz Nowy wątek
2011-08-07 12:40
0

Mam przykładowy program

#include <stdio.h>
#include <stdint.h>
int main()
{
   uint64_t x = (uint64_t)1 << 31;
   uint64_t y = (uint64_t)(1 << 31);
   uint64_t z = 1 << 31;
   printf("%lli\n%lli\n%lli\n", x, y, z); 
   return 0;
}

Po uruchomieniu dostaję wynik:

2147483648
-2147483648
-2147483648

Może mi ktoś wyjaśnić dlaczego te trzy zmienne nie mają takiej samej wartości?

edytowany 1x, ostatnio: lukasz1235, 2011-08-07 12:40

Pozostało 580 znaków

2011-08-07 12:54
0
uint64_t x = (uint64_t)1 << 31;

wartość 1 typu uint64_t jest przesuwana o 31 typu int bitów w lewo. wynik operacji jest typu uint64_t jako szerszy z dwóch. następnie wynik jest przypisany do zmiennej typu uint64_t.

uint64_t y = (uint64_t)(1 << 31);

wartość 1 typu int jest przesuwana o 31 typu int bitów w lewo. wynik operacji jest typu int. dalej wynik jest rzutowany na typ uint64_t i przypisany do zmiennej o tymże typie.

uint64_t z = 1 << 31;

wartość 1 typu int jest przesuwana o 31 typu int bitów w lewo. wynik operacji jest typu int, przypisany do zmiennej o typie uint64_t.

tylko w pierwszym przypadku wynikiem przesunięcia jest uint64_t, w pozostałych rzutowanie następuje już po operacji bitowej.

edytowany 4x, ostatnio: Azarien, 2011-08-07 12:57

Pozostało 580 znaków

2011-08-07 15:32
0

Dzięki, ale i tak mi się coś nie zgadza:

#include <stdio.h>
#include <stdint.h>
int main()
{
   uint64_t i = 31;
   uint64_t z = 1 << i;
   printf("%lli\n", z); 
   return 0;
}

Daje:
-2147483648

Pozostało 580 znaków

2011-08-07 17:41
0

Źle wypisujesz: uint64_t jest unsigned: printf("%llu\n", z);


Pozostało 580 znaków

2011-08-07 19:22
0

W tym wypadku wypisywanie nie ma żadnego znaczenia.

Pozostało 580 znaków

2011-08-07 19:26
0

Skoro dla Ciebie to nie robi różnicy:

poprawne: 18446744071562067968
błędne:   -2147483648

no to spoko

dodatkowo to 1 << i przesuwa bity o 31 miejsc, ale w typie int, a nie uint64_t - w sumie nie wiem dlaczego tak jest(kolejna niekonsekwencja języka?). Musisz wykonać rzutowanie (uint64_t)1 << i;


edytowany 4x, ostatnio: byku_guzio, 2011-08-07 19:31
Może i niekonsekwencja ale logiczna - czytamy przesuń &lt;int&gt; o &lt;liczba&gt; miejsc czyli przesuwamy inta. Tak mi się przynajmniej wydaje - msm 2011-08-07 19:38
no tak, ale skoro drugim argumentem jest większy typ to powinna nastąpić promocja tego inta. Przynajmniej tak jak to jest z operatorami arytmetycznymi. Byłoby to przynajmniej spójne - byku_guzio 2011-08-07 19:44
Drugi argument też jest intem, więc wynik jest intem. Należy też pamiętać, że 1<<33 może wypuścić demony z nosa. - Zjarek 2011-08-07 20:20
Zgodnie ze standardem ma prawo wysłać twoje nagie fotki na facebooka :P - msm 2011-08-07 20:22
@Zjarek: drugi argument nie jest intem a uint64_t (unsigned long long int) - byku_guzio 2011-08-07 20:23
Obie liczby to tylko inna reprezentacja tej samej wartości więc nie robi to różnicy. - lukasz1235 2011-08-07 20:32

Pozostało 580 znaków

2011-08-07 20:36

Dokumentacja mówi:

The type of the result is that of the promoted left operand.
Czyli wszystko jasne, tylko szkoda że nieintuicyjne :/ W każdym razie dzięki.

edytowany 1x, ostatnio: lukasz1235, 2011-08-07 20:37

Pozostało 580 znaków

2011-08-07 20:48
0

Tylko dlaczego wartość jest promowana tylko do (unsigned) inta (tzn. wiem dlaczego, tak mówi standard, ale jest to nielogiczne), np. w tym przykładzie:

#include <cstdio>
using namespace std;
int main(){
    short i=1;
    printf("%d\n", sizeof i);
 
    unsigned long long t=i<<31;
    printf("%llu\n",t);
 
}

Pozostało 580 znaków

2011-08-07 21:04
0

Standard wyraźnie mówi, że promocje są tylko do int lub unsigned int, a że nielogiczne to już inna sprawa.

A dokładnie:

An rvalue of type char, signed char, unsigned char, short int, or unsigned short int can be converted to an rvalue of type int if int can represent all the values of the source type; otherwise, the source rvalue can be converted to an rvalue of type unsigned int.

edytowany 3x, ostatnio: lukasz1235, 2011-08-07 21:15

Pozostało 580 znaków

2011-08-08 09:19
0

@lukasz1235: Zresztą za taki kod powinieneś zostać spalony na stosie (nie, nie na tym w komputerze), bo poleganie na tym jak akurat w danym miejscu się spromuje wartość stała jest po prostu nieprofesjonalne.

Jeśli chcesz mieć stałą nieznakowaną to zajrzyj tutaj:
http://msdn.microsoft.com/en-[...]ry/00a1awxf%28v=vs.80%29.aspx
http://cpp.comsci.us/etymology/literals.html

A jeśli nie chcesz / nie możesz użyć stałej nieznakowanej, to ją konwertujesz jawnie - jak w przykładzie 1, wersja 1.

edytowany 1x, ostatnio: vpiotr, 2011-08-08 09:24

Pozostało 580 znaków

2011-08-08 10:30
0

Za jaki kod? Ja po prostu podałem kilka przykładów (zresztą niezbyt trafionych, bo od początku wartość 31 powinna być typu uint64_t). A w kodzie oczywiście używam jawnego rzutowania.

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0