Почему семейство функций stdlib.h abs() возвращает знаковое значение?

Отрицательная импликация этого отмечена на странице руководства:

ПРИМЕЧАНИЯ        Попытка взять абсолютное значение наибольшего отрицательного целого не        определены.

Каковы причины этого и что лучше всего подходит человеку, который хотел бы избежать поведения undefined? Должен ли я прибегать к чему-то вроде:

unsigned uabs(signed val) {
    return val > 0
        ? val
        : (val == 1U << ((sizeof(val) * 8) - 1))
            ? -1U
            : -val;
}

(Преднамеренно взломано, чтобы подчеркнуть неудовольствие stdlib;)

Пример

Скажем, у вас было 4-значное значение знака (для удобства понимания). unsigned max - 15, подписанный (положительный) max равен 7, знак (отрицательный) min равен -8, поэтому abs (-8) не будет вписываться в значение со знаком. Конечно, вы можете представить его как -8, но тогда деление и умножение с результатом не работают должным образом.

Ответ 1

Реальный ответ на этот вопрос лежит в правилах продвижения по типу.

Если я применяю арифметический оператор к unsigned int и int, то аргумент int получает значение unsigned, а результат также unsigned.

Если функция abs() вернула unsigned, то это приведет к такому типу продвижения других значений, когда она была использована в выражении, что приведет к неожиданным результатам. Например, этот код:

if (abs(-1) * -1 < 0)
    printf("< 0\n");
else
    printf(">= 0\n");

Будет печатать " >= 0", что многим не понравится. Компромисс, неспособный использовать одно значение INT_MIN, предположительно, выглядит ОК.

Ответ 2

Почему он когда-либо возвращал значение с использованием неподписанного пространства?

Рассмотрим 8-битные подписанные и неподписанные числа. Если у вас есть -128, результат будет undefined... Я думаю, stdlib не хочет замедлять это. Если вы думаете, что у вас может быть номер в этом диапазоне, вам нужно использовать что-то еще.

Если вы считаете, что в подписанном char значении, превышающем 127, вы ошибаетесь.

Ergo, нет необходимости, чтобы значение могло удерживать значение, превышающее 127, и сохранение его подписи ничего не теряет. Если вы хотите отдать его без знака, продолжайте. Поскольку он просто использовался как целое число со знаком, шансы хорошие, что вы снова будете выполнять подписанную математику. Лично я думаю, что я предпочел бы, чтобы тип оставался подписанным, так как довольно редко, что я действительно хочу иметь дело с unsigned, и я не выполняю операции с битами.

Но, возможно, кто-то еще может выкопать некоторые заметки из комитета по стандартам.