Условный оператор: преобразование из «int» в «unsigned char», возможная потеря данных - PullRequest
2 голосов
/ 24 мая 2011

У меня есть следующий код C:

a = (b == B1) ? A1 : A2;

a, b, A1, A2 и B1 относятся к типу unsigned char. A1, A2 и B1 - все константы.

При компиляции под VC ++ я вижу следующее предупреждение:

warning C4244: '=' : conversion from 'int ' to 'unsigned char ', possible loss of data

Я не понимаю это предупреждение - ни одна из переменных не имеет тип int. Предположительно происходит какое-то неявное преобразование, но почему?

Странно, но следующий код (который функционально идентичен) компилируется без предупреждений:

if (b == B1) {
  a = A1;
} else {
  a = A2;
}

Насколько я знаю, два фрагмента кода должны быть идентичны.

Ответы [ 3 ]

4 голосов
/ 24 мая 2011

В языке C арифметические аргументы троичного оператора ?: подвергаются обычным арифметическим преобразованиям, т. Е. Они повышаются до int перед выполнением любых дальнейших вычислений. Не имеет значения, являются ли они постоянными или нет. Важно то, что они имеют тип unsigned char (как вы сказали), и unsigned char в ?: всегда продвигается первым. По сути, язык C никогда не выполняет никаких вычислений в типах, меньших int. Все, что меньше, сначала преобразуется в int.

Это то, что происходит и в вашем случае. В основном, ваш

a = (b == B1) ? A1 : A2;

интерпретируется языком C как

a = ((int) b == (int) B1) ? (int) A1 : (int) A2;

и вот почему вы получаете предупреждение. Опять же, тот факт, что A1 и A2 являются константами, не играет никакой роли.

a = A1;

не подвергает правую часть интегральному продвижению, поэтому здесь нет никаких предупреждений. Более того, в этом тривиальном случае (прямое присваивание), даже если A1 было явно объявлено как константа int, большинство компиляторов не будут выдавать предупреждение, если увидят, что константа находится в диапазоне целевого типа unsigned char. Случай с ?: более сложный, поэтому компиляторы могут вернуться к общему поведению и выдать предупреждение.

3 голосов
/ 24 мая 2011

Хотя функционально то же самое, оба кода не совсем равны.

Видите ли, когда вы используете троичный оператор, то есть condition ? true_value : false_value, компилятор пытается вывести между значениями наилучший возможный тип.

Поскольку A1 и A2 являются постоянными (как вы указали в O.P.), компилятор заменяет их положение их действительными значениями, полностью игнорируя тип данных, отображая оба значения как целые.

Отсюда необходимость приведения результата как такового:

a = (unsigned char)((b == B1) ? A1 : A2);
2 голосов
/ 24 мая 2011
  a = (unsigned char)((b == B1) ? A1 : A2);

Я полагаю, это потому, что в выражениях sub нет значений r - они автоматически преобразуются в int в лексере. Приведенный выше код должен устранить предупреждение и не повлиять на полученный код.

...