Próbuję zrozumieć mechanikę następującej konwersji

#include <stdio.h>
#include <stdint.h>

int main() {
    
    int a = 0xffffffff;  
    printf("%d", a); // prints -1
    return 0;
}

Według Ciała całkowita typ 0xffffffff to {{x1 }}. Można to łatwo sprawdzić, robiąc printf("%s", 0xffffffff);

Teraz, zgodnie z Semantyka konwersji wewnętrznej:

"Promocja całkowita jest ukrytą konwersję wartości dowolnego typu całkowitego z rangi mniejszą lub równą rangi Int [...] do wartości typu INT lub niepodpisany."

I, jak stwierdzono poniżej

"Rangi wszystkich podpisanych typów całkowitych równych szeregach odpowiednich niepodpisanych typów całkowitego"

Więc dotyczy promocji, ponieważ ranga unsigned int jest taka sama jak ranga int.

Promocja jest zdefiniowana jako

"Jeśli int może reprezentować całą gamę wartości typu oryginalnego (lub zakresu wartości oryginalnego pola bitów), wartość jest konwertowana na typ Int. W przeciwnym razie wartość jest konwertowana na niepodpisany INT"

Ale i to jest to, czego nie rozumiem, int nie może reprezentować unsigned int 4,294,967,295, ale nadal jest konwertowany na int. I tak się dzieje bez ostrzeżenia o zawaleniu . Dlaczego tak jest?

1
perencia 14 marzec 2021, 01:57

1 odpowiedź

Najlepsza odpowiedź

Ponieważ stała {x0}}, która (zakłada {x1}} to 32 bitów) ma typ unsigned int, jest używany do zainicjowania obiektu typu {x3}}, obejmuje to konwersję z { {X4}} do int.

Konwersja między typami całkowitymi opisano w rozdziale 6.3.1.3 standardu C:

1 Gdy wartość z typem całkowitym jest konwertowana na inny typ całkowitego inny niż _Bool, jeśli wartość może być reprezentowana przez nowy Wpisz, niezmieszczony.

2 w przeciwnym razie, jeśli nowy typ jest niepodpisany, wartość jest konwertowana przez wielokrotnie dodawanie lub odejmowanie więcej niż Maksymalna wartość, która może być reprezentowana w nowym typ aż wartość nie jest w zakresie nowego typu.

3 w przeciwnym razie podpisany jest nowy typ, a wartość nie może być w niej reprezentowana; Albo wynikiem jest zdefiniowany implementację lub sygnał zdefiniowany przez wdrożenie jest podniesiony

Ustęp 3 jest tym, co dotyczy w tym przypadku. Dane wartości jest poza zakresem typu miejsca docelowego, a miejsce docelowe jest podpisane. Więc nastąpiła konwersja zdefiniowana implementacja.

Jeśli skompilujesz z GCC za pomocą flagi {x0}}, da Ci ostrzeżenie:

x1.c:6:5: warning: conversion of unsigned constant value to negative integer [-Wsign-conversion]
     int a = 0xffffffff;  

Również:

Można to łatwo sprawdzić, robiąc printf("%s", 0xffffffff);

To wywołuje Nieodefiniowane zachowanie Ponieważ %s Specyfikator formatu oczekuje, że char * co wskazuje na link końcowy. Wartość, którą przechodzisz, nie jest tego typu i prawdopodobnie nie jest prawidłowym adresem pamięci.

Promocje całkowite nie dotyczą również tutaj, ponieważ nie ma wyrazu z typem niższej rangi niż int lub unsigned int.

4
dbush 13 marzec 2021, 23:14