Dziwne zachowanie rzutowania

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?

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.

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

0

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

0

W tym wypadku wypisywanie nie ma żadnego znaczenia.

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;

0

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.

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);
		
}
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.

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-us/library/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.

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.

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