programowanieProgramista C

Jakie zasady konwersji typów (type conversion, type promotion) stosowane są w wyrażeniach w języku C? Podaj przykłady niespodziewanych błędów i rozwiązań.

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

W języku C w wyrażeniach często zachodzą konwersje typów (type promotion, type conversion), regulowane standardem:

  • Promocja całkowita: typy o mniejszej precyzji (na przykład char, short) automatycznie konwertowane są na int lub unsigned int przed operacjami arytmetycznymi.
  • Zwykłe konwersje arytmetyczne: jeśli operandy mają różne typy - zostają konwertowane do "szerszego" typu zgodnie z określonymi zasadami.
  • Przy mieszanych operacjach z typami signed i unsigned wynik może niespodziewanie się zmienić z powodu konwersji.

Przykład:

unsigned short a = 65535; signed short b = -1; printf("%d ", a + b); // zależy od konwersji!

Zalecenie: uważnie obserwuj typy operandów, szczególnie przy pracy z operacjami bitowymi, długościami tablic, indeksami i unikaj niejawnego mieszania typów signed i unsigned.

Pytanie z haczykiem

Co wyświetli poniższy fragment?

unsigned int u = 1; int i = -2; printf("%d ", u + i);

Odpowiedź: Zmienna i zostanie skonwertowana na unsigned int, a końcowa wartość stanie się bardzo duża, ponieważ wynik pod maską: 1U + (unsigned int)-2U, co da liczbę bliską UINT_MAX (4294967295). Zostanie wydrukowana liczba ujemna tylko jeśli printf będzie formatować jako int, w przeciwnym razie śmieci.

Przykłady rzeczywistych błędów z powodu niewiedzy na temat szczegółów tematu


Historia

Podczas obliczania średnich wartości intensywności obrazu pomylono int z unsigned int. Ujemne wartości błędnie konwertowane przez unsigned dawały ogromne liczby, prowadząc do przepełnienia bufora obrazu.


Historia

W wbudowanym oprogramowaniu obliczano długość łańcucha jako size_t, a indeksowano tablicę przez int. Przy sprawdzaniu warunku przekroczenia granic tablicy porównywano int i >= size_t len, co łamało logikę dla długich łańcuchów i powodowało błędy podczas porównania różnych typów (size_t — unsigned).


Historia

Programista przy projekcie finansowym obliczał resztę z dzielenia dla liczb ujemnych przez %, zapominając, że znak wyniku dla ujemnych operandów zależy od implementacji. W jednym środowisku wynik był dodatni, w innym – ujemny, co powodowało okresowe "zakłócenia" obliczeń.