Co zwróci funkcja?

0

Zakłada się, że zmienne typu int zajmują dwa bajty i są pamiętane w kodzie U2. Zakłada się ponadto, że
komputer, na którym implementowany jest poniższy program nie sygnalizuje błędów spowodowanych
przekroczeniem zakresu wartości zmiennych. Jak zakończy się działanie poniższego programu?

int main () {
 const int maxint = 32767;
 int a = maxint-4;
 int b = 5;
 while (a<maxint) {
 a--;
 b++;
 }
 cout << b;
}

A drugie pytanie mam takie: co zwróci funkjca abs() dla najbardziej ujemnej liczby?

0

Chodziło może bardziej co wypisze (jakie b)

0

Jak na moje masz UB. Nie ważne, że 'komputer nie sygnalizuje błędów', kompilator może przy cout << b wypisać choinkę.

5

Mamy UB tutaj. Czytamy:

When signed integer arithmetic operation overflows (the result does not fit in the result type), the behavior is undefined: it may wrap around according to the rules of the representation (typically 2's complement), it may trap on some platforms or due to compiler options (e.g. -ftrapv in GCC and Clang), or may be completely optimized out by the compiler.

0

Żadne tam UB, po prostu nastąpi przekręcenie zakresu a i b. Na mojej maszynie, gdzie wielkość a i b to 4 bajty, dla b pokazał -2147450879.
A tu przykład jak to działa (wymaga C++14):

#include <iostream>

int main()
{
    std::cout << "Przykład przekręcania licznika -1 (zapis binarny 8x1111B) do 0\n";
    int a = 0b1111'1111'1111'1111'1111'1111'1111'1111;
    std::cout << "a =" << a << ", a + 1 = " << a + 1 <<"\n";
    
    std::cout << "Przykład przekręcania licznika z liczby ujemnej do dodaniej (zapis binarny 1(0)B)\n";
    int b = 0b1000'0000'0000'0000'0000'0000'0000'0000;
    std::cout << "b =" << b << ", b - 1 = " << b - 1;

    return 0;
}

https://onlinegdb.com/SkMkjjRVE

2

Największa i najmniejsza możliwa wartość typu int w systemach 64-bitowych to + 2 147 483 647 oraz - 2 147 483 648 (wielkości stałych symbolicznych preprocesora znajdziesz w pliku <climits>).
Program w kolejnych pętlach zmniejsza a i zwiększa b . Zmienne **a ** i **b ** będą zachowywały się jak licznik kilometrów. Z chwilą przekroczenia wartości -2 147 483 648 a będzie zaczynała zmniejszanie od 2 147 483 647. Po przekroczeniu + 2 147 483 647 b będzie się zwiększało od - 2 147 483 648. Jak obliczyć b na koniec działania programu? Obliczasz ilośc razy jaką trzeba zmniejszyć a, aby spełniony był warunek wyjścia z pętli, czyli =32763-(-2147483648)=2 147 516 411 razy. Ponieważ b brakuje do "przekręcenia licznika: 2147483647-5=2 147 483 642 zwiększeń, obliczamy 2 147 516 411 - 2 147 483 642 = 32 769, A następnie zliczamy ile razy b zwiększy się już po przękręceniu licznika - 2 147 483 648+32 769=-2 147 450 879. Odpowiedź: b zatrzyma się na wartości -2 147 450 879, abs(b)=2 147 450 879

Dość upierdliwe to zadanie. Nauczyciel sadysta. Szkoda czasu na naukę czegoś takiego. Życie płynie.

0
maciox123 napisał(a):

A drugie pytanie mam takie: co zwróci funkjca abs() dla najbardziej ujemnej liczby?

Mały niuansik, o którym nie należy zapominać. Najmniejszą wartością jaka przyjmie b w trakcie wykonywania kodu będzie: -2147483648, czyli abs(min{b})=2 147 483 648

0

@MasterBLB: Mimo wszystko można się łatwo naciąć przy przekręcaniu signed.

#include <iostream>
#include <limits>

int main(int, char**)
{
  int value = std::numeric_limits<int>::max();
  std::cout << val + 1 << " > " << val << " ? => " << std::boolalpha << (val + 1 > val) << "\n";
  return 0;
}

Bez optymalizacji dostaniesz false, z optymalizacją dostaniesz true ;)

2

Żeby było jasne Undefined Behavior w C++ oznacza, że standard nie nakłada żadnych więzów na implementację jaką ma wykonać kompilator.
Celem Undefined Behavior w standardzie C i C++, jest danie takiej wolności implementacji kompilatora, by kod działał szybko na każdej możliwej maszynie.
Jeśli jest jakaś dziwna platforma, to kompilator nie powinien być zmuszony do emulowania zachowania popularnych platform.

Przepełnienie dla unsigned int jest niezdefiniowane w standardzie, bo po prostu nie wszystkie platformy używają U2 (takich maszyn które nie stosują U2 jest niewiele, większość starsza niż 30 lat, ale istnieją i standard musi je uwzględniać).
Mało tego istnieją maszyny, które stosują w obliczaniach całkowitych system dziesiętny (cyfry dziesiętne zapisane są binarnie, ale obliczania są robione w systemie dziesiętnym).

Tak samo standard nie definiuje co się powinno stać jeśli wskaźnik pokazuje na zły obiekt.
Generalnie chodzi mi o to, że Undefined Behavior wcale nie musi oznaczać błędu albo crash-a.

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