Я пытаюсь понять правила неявного преобразования в C ++, и я понял, что когда есть одна операция между двумя основными типами, «нижний тип» переводится в «более высокий тип», поэтому, скажем, для:
int a = 5;
float b = 0.5;
std::cout << a + b << "\n";
должен напечатать 5.5, потому что ‘a’ повышен до типа с плавающей точкой. Я также понял, что неподписанные типы являются «более высокими типами», чем подписанные части счетчика, поэтому:
int c = 5;
unsigned int d = 10;
std::cout << c - d << "\n";
печатает 4294967291, потому что ‘c’ переводится в unsigned int, и так как типы unsigned оборачиваются, когда меньше нуля, мы получаем это большое число.
Однако в следующем случае я не понимаю, почему я получаю -105 вместо положительного числа.
#include <iostream>
int main(void) {
unsigned char a = 150;
std::cout << static_cast<int>(a - static_cast<unsigned char>(255)) << "\n";
return 0;
}
Я думаю, что этот код:
a - static_cast<unsigned char>(255)
должно приводить к положительному числу, чтобы окончательное приведение (к int) не влияло на конечный результат, верно?
Цитировать из C++14
Глава § 5.7
Аддитивные операторы
+
а также-
группа слева направо. Обычные арифметические преобразования выполняются для
операнды арифметического или перечислимого типа.
и для обычные арифметические преобразования, (специально для этого случая)
….
- В противном случае интегральные преобразования (4.5) должны выполняться для обоих операндов.
и, наконец, для интегральные акции, глава § 4.5
Значение типа integer, отличного от
bool
,char16_t
,char32_t
, или жеwchar_t
чье целочисленное преобразование
rank (4.13) меньше ранга int, который можно преобразовать в тип prvalueint
если int может представлять все
значения типа источника; в противном случае исходное значение может быть преобразовано в значение типаunsigned
int.
Следовательно unsigned char
операнды повышены до int
а затем, результат рассчитывается.
Вы пропускаете (неявное) преобразование из unsigned char
в int
что происходит, чтобы выполнить -
(вычесть) операцию. Это целочисленное продвижение происходит каждый раз, когда вы пытаетесь применить любую целочисленную операцию к значению некоторого целочисленного типа, меньшего, чем int
,
Здесь есть ответы, показывающие, что происходит. Я не буду повторяться Я собираюсь дать вам простой инструмент, чтобы помочь вам.
Вот трюк, который вы можете сделать, чтобы быстро найти тип выражения:
template <class> struct Name; // purposely no definition given
Name<decltype(your_expression)> n;
Это сгенерирует ошибку компилятора для неопределенного шаблона «Имя», но на самом деле нас интересует тип аргумента шаблона, который появится в сообщении об ошибке.
Например. если вы хотите увидеть, какой тип вы получаете, когда вы делаете арифметику между двумя unsigned char
:
#include <utility>
template <class> struct Name;
auto test()
{
Name<decltype(std::declval<unsigned char>() - std::declval<unsigned char>())> n;
// or
unsigned char a{};
Name<decltype(a - a)> n2;
}
получу тебя
error: implicit instantiation of undefined template 'Name<int>'
который покажет вам, что тип выражения int
Конечно, это не скажет вам, какие правила применяются, но это быстрая отправная точка, чтобы увидеть тип выражения или проверить ваше предположение о типе выражения.