Porównywanie liczb całkowitych ze znakiem i bez znaku

0
unsigned int c=5;
printf("%d %d %d",-c,-5==-c,1>(-c));
unsigned short d=5;
printf("%d %d %d",-d,-5==-d,1>(-d));

wyswietla -5 1 0 -5 1 1

Moze mi to ktos wyjasnic ?

2

Masz unsigned a w printf używasz %d, które oczekuje int (w domyśle, signed).

0

no jak masz prawdziwy warunek, to wyświetli się jako 1, a fałszywy jako 0.
nie jestem natomiast pewien o co chodzi z tymi dwoma warunkami, które są podawane jako ostatnie do funkcji printf.
zapewne chodzi o to, że masz unsigned, ale czemu się inaczej renderują, skoro i tu i tu jest unsigned, tylko inne?

swoją drogą głupi język, że da się coś takiego robić. A JS ludzie hejtują.

tu coś piszą o czymś podobnym https://stackoverflow.com/questions/25811220/unsigned-short-and-signed-short-comparison-wierd-behavior

0

Liczby ujemne są konwertowane na naturalne i potem następuje porównanie.

2
LukeJL napisał(a):

zapewne chodzi o to, że masz unsigned, ale czemu się inaczej renderują, skoro i tu i tu jest unsigned, tylko inne?

To jest pewnie całkowicie uzasadnione i zgodne ze standardem, ale kto by się wdawał w takie szczegóły dlaczego dla unsigned int jest inny wynik niż dla unsigned short. Wyjeżdżasz poza zakres typu więc wynik jest zły.

Skojarzenie z JS wydaje się właściwe :)

2

ale czemu się inaczej renderują, skoro i tu i tu jest unsigned, tylko inne?

Bo okazuje się, że operacja dopełnienia dwójki, czym - właściwie jest, automatycznie konwertuje unsigned short na int, dlatego porównania do literałów liczb, które są int by default dają spodziewane wyniki. W tym samym czasie, dopełnienie dwójki na unsigned int pozostawia typ nie zmieniony przez co jak wspomniał @Azarien, wyjeżdżamy poza zakres i mogą się dziać cuda.

Cytaty ze standardu C++, czy w C jest identycznie to nie wiem.

10 Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield result types in a
similar way. The purpose is to yield a common type, which is also the type of the result. This pattern is called the usual
arithmetic conversions, which are defined as follows:

— Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with
unsigned integer type, the operand with unsigned integer type shall be converted to the type of the operand with signed integer type.

Dowód na zmianę typu https://wandbox.org/permlink/VIC1adioxLb7moLR

#include <cxxabi.h>

static std::string demangle(const char* name)
{
  int status = -4;
  char* res = abi::__cxa_demangle(name, NULL, NULL, &status);
  const char* const demangled_name = (status==0)?res:name;
  std::string ret_val(demangled_name);
  free(res);
  return ret_val;
}

int main()
{
  unsigned int c=5;
  unsigned short d=5;
  std::cout << demangle(typeid(d).name()) << " becomes " << demangle(typeid(-d).name()) << "\n";
  std::cout << demangle(typeid(c).name()) << " becomes " <<demangle(typeid(-c).name()) << "\n";
  
  return 0;
unsigned short becomes int
unsigned int becomes unsigned int

Podsumowując, trochę jaja i kolejny dowów na to, że niejawna konwersja typów to zło.

0
ROSY napisał(a):
unsigned int c=5;
printf("%d %d %d",-c,-5==-c,1>(-c));
unsigned short d=5;
printf("%d %d %d",-d,-5==-d,1>(-d));

wyswietla -5 1 0 -5 1 1

Moze mi to ktos wyjasnic ?

Jak masz int c=5 to tam znaczek +/- jest już ustawiony.
Potrzebujesz zamienić te (zapewne) 4 bajty na 32 bity (w pętli która się uruchomi 32 razy) i (chyba) 0 wy element zamienić z 1 na 0 albo z 0 na 1
I wtedy będziesz miał -5
Albo zrobić wskaźnik typu unsigned char u stawić jego adres na początek tego typu int i ustawić mu wartość na -5.
Chyba aż sam to przetestuję.

0

rozważ taki program:

#include <stdio.h>

int main(void) {
    unsigned int c = 5;
    unsigned short d = 5;

    printf("c = %032b %d\n", c, c);
    c = -c;
    printf("c = %032b %d(U2) %u\n", c, c, c);

    printf("\nd = %032b %d\n", d, d);
    d = -d;
    printf("d = %032b %d %u\n", d, d, d);
    printf("d = %hd %hu\n", d, d);

    return 0;
}
c = 00000000000000000000000000000101 5
c = 11111111111111111111111111111011 -5(U2) 4294967291

d = 00000000000000000000000000000101 5
d = 00000000000000001111111111111011 65531 65531
d = -5 65531

przy operacji c = -c typ unsigned int został pewnie(?) wypromowany do większego signed long a potem to zostało zanegowane, czyli w systemie U2 bity są zamieniane (1->0, 0->1) i dodawana jest 1. Potem przypisanie z powrotem do mniejszego typu, więc zostają obcięte starsze bajty.

Funkcja printf z opcją %d pokaże -5, z opcją %u liczbę 4294967291. Nie ma tu nic dziwnego, obie liczby to ta sama sekwencja bitów tylko printf różnie ją wyświetla w zależności od użytego formatu.

Dla d funkcja printf z opcją %d lub %u wyświetli 65531 bo oczekuje int-a więc z mniejszego typu unsigned short przekształci go na większy uzupełniając go zerami bo jest unsigned (typ signed uzupełnia jedynkami). Przy opcji %hd (prawidłowej dla short) wyświetli -5 bo sekwencja bitów 1111111111111011 w U2 ma właśnie taką postać. Opcja %hu jest dla unsigned short i wyświetli 65531, którego bity są identyczne jak dla -5.

porównywanie typów ze znakiem z typami bez znaku jest trochę niebezpieczne, rozważ poniższy program i ostrzeżenia kompilatora:

unsigned int c = 5;
int i = 1;
bool b = i < (-c);
main.c: In function ‘main’:
main.c:20:16: warning: comparison of integer expressions of different signedness: ‘int’ and ‘unsigned int’ [-Wsign-compare]
   20 |     bool a = i > (-c);
      |

int porównuje unsigned int. Kompilator jakoś nie wypromował (-c) do większego typu i skończył na unsigned int.

Bezpieczniej byłoby samemu ustawić większy typ, np. tak:

bool b = 1 < (-(long long)c);
0
johnny_Be_good napisał(a):

Albo zrobić wskaźnik typu unsigned char u stawić jego adres na początek tego typu int i ustawić mu wartość na -5.

To jest prawie na pewno undefined behavior (zależy co masz dokładnie na myśli i jak to zakodzisz).

0

W konwertowaniu nie jest nic zlego, ale mogl by to robic lepiej... Wszystkie popularne obecnie jezyki sa pokrecone, jak caly swiat...

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