Dowiaduję się o przeciążaniu funkcji w C ++ i natknąłem się na to:
void display(int a)
{
cout << "int" << endl;
}
void display(unsigned a)
{
cout << "unsigned" << endl;
}
int main()
{
int i = -2147483648;
cout << i << endl; //will display -2147483648
display(-2147483648);
}
Z tego, co zrozumiałem, każda wartość podana w int
zakresie (w moim przypadku int
to 4 bajty) zostanie wywołana, display(int)
a każda wartość spoza tego zakresu będzie niejednoznaczna (ponieważ kompilator nie może zdecydować, którą funkcję wywołać). Obowiązuje dla całego zakresu int
wartości z wyjątkiem jego wartości minimalnej, tj. -2147483648
Gdy kompilacja kończy się niepowodzeniem z powodu błędu
wywołanie przeciążenia
display(long int)
jest niejednoznaczne
Ale biorąc tę samą wartość do an int
i wypisując wartość daje 2147483648
. Dosłownie jestem zdezorientowany tym zachowaniem.
Dlaczego to zachowanie jest obserwowane tylko wtedy, gdy zostanie przekazana najbardziej ujemna liczba? (Zachowanie jest takie samo, jeśli a short
jest używane z -32768
- w rzeczywistości w każdym przypadku, gdy liczba ujemna i liczba dodatnia mają tę samą reprezentację binarną)
Używany kompilator: g ++ (GCC) 4.8.5
źródło
call of overloaded ‘display(long int)’ is ambiguous
.typeof(-2147483648) != int
. Dosłowne to2147483648
, które jest za duże na anint
, więc to jestlong
i jest negowaneint j{-2147483648};
jest to zawężająca konwersja. Prawie warto zadać sobie to pytanie. Prawdopodobnie jest to związane z dopuszczaniem (np.)long long
Wartości constexpr, takich jak2147483647LL
zawężanie podczas inicjalizacji.Odpowiedzi:
To bardzo subtelny błąd. To, co widzisz, jest konsekwencją braku ujemnych literałów całkowitych w C ++. Jeśli spojrzymy na [lex.icon], otrzymamy literał całkowity ,
może być literą dziesiętną ,
gdzie cyfra jest
[0-9]
i niezerowe-cyfrowy jest[1-9]
i par sufiks może być jedenu
,U
,l
,L
,ll
, iLL
. Nigdzie tutaj nie jest to-
część literału dziesiętnego.W §2.13.2 mamy również:
(podkreślenie moje)
Co oznacza, że
-
in-2147483648
jest jednostką jednoargumentowąoperator -
. Oznacza to, że-2147483648
jest faktycznie traktowany jako-1 * (2147483648)
. Ponieważ2147483648
jest o jeden za dużo dla Ciebieint
, jest promowany do a,long int
a niejednoznaczność wynika z tego, że nie pasuje.Jeśli chcesz uzyskać minimalną lub maksymalną wartość dla typu w sposób przenośny, możesz użyć:
std::numeric_limits<type>::min(); // or max()
źródło
-2147483647 - 1
działałby również bez ostrzeżenia jako negatywne wyrażenie dosłowneINT_MIN
najmniej szczegółowa opcja. Jednak mniej ogólne.display(2147483649);
. Dlaczego w tym przypadku nie może wywołać funkcji int bez znaku? i dlaczego traktuje argument2147483649
jako long int zamiast unsigned int?int
dolong int
dolong long int
. Nigdy nie otrzymasz typu bez znaku dla literału dziesiętnego, chyba że użyjesz sufiksuu
/U
.display(unsigned a)
, potrzebujesz albodisplay(1234u);
lubdisplay(static_cast<unsigned>(1234));
albounsigned foo = 1234; display(foo);
Wyrażenie w
-2147483648
rzeczywistości stosuje-
operator do stałej2147483648
. Na Twojej platformieint
nie można przechowywać2147483648
, musi być reprezentowany przez większy typ. Dlatego wyrażenie-2147483648
nie jest wyprowadzona byćsigned int
jednak większa podpisał typ,signed long int
.Ponieważ nie zapewniasz przeciążenia,
long
kompilator jest zmuszony wybrać między dwoma przeciążeniami, które są jednakowo prawidłowe. Twój kompilator powinien wygenerować błąd kompilatora dotyczący niejednoznacznych przeciążeń.źródło
Poszerzanie odpowiedzi innych
Aby wyjaśnić, dlaczego PO jest zdezorientowany, najpierw : rozważ
signed int
binarną reprezentację2147483647
poniżej.Następnie dodaj jeden do tego numeru : podając inny
signed int
z-2147483648
(którego PO chce użyć)Wreszcie: widzimy, dlaczego OP jest zdezorientowany podczas
-2147483648
kompilacji do along int
zamiast asigned int
, ponieważ wyraźnie mieści się w 32 bitach.Ale, jak wspominają obecne odpowiedzi, operator jednoargumentowy (
-
) jest stosowany po rozwiązaniu,2147483648
który jest along int
i NIE mieści się w 32 bitach.źródło