Правильно, исходный операнд определяет это.
uint32_t a = -1;
int64_t b = (int64_t) a;
Здесь не происходит расширения знака, поскольку исходное значение - без знака uint32_t
. Основная идея расширения знака состоит в том, чтобы гарантировать, что более широкая переменная имеет то же значение (включая знак). Исходя из целого типа без знака, значение всегда положительное. Это описано во фрагменте стандартов /1
ниже.
Расширение отрицательного знака (в том смысле, что старший 1-бит в значении дополнения до двух копируется во все старшие биты в более широком типе (a) ) происходит только тогда, когда тип со знаком расширяется по ширине, поскольку только типы со знаком могут быть отрицательными.
Если исходное 32-разрядное число является знаковым и отрицательным, приведение его к 64-разрядному значению добавит 1 слева от него независимо от того, какое значение назначения подписано или не подписано.
Это описано в фрагменте стандартов /2
ниже. Вы все еще должны поддерживать знак значения при расширении битов, но вставка отрицательного значения (при условии, что источник был отрицательным) в переменную без знака просто математически добавляет MAX_VAL + 1
к значению, пока оно не станет в пределах диапазона целевого типа (в действительности, для дополнения до двух добавление не выполняется, оно просто интерпретирует одну и ту же битовую комбинацию по-разному).
Обе эти сцены ios покрыты в стандарте, в данном случае C11 6.3.1.3 Signed and unsigned integers /1
и /2
:
1 / Когда значение с целочисленным типом преобразуется в другой целочисленный тип, отличный от _Bool
, если значение может быть представлено новым типом оно не изменяется.
2 / В противном случае, если новый тип является беззнаковым, значение преобразуется путем многократного сложения или вычитания на единицу больше максимального значения, которое может быть представлено в новом типе, до значение находится в диапазоне нового типа.
3 / В противном случае новый тип подписывается и значение не может быть представлено в нем; либо результат определяется реализацией, либо определяется сигнал реализации.
Обратите внимание, что ваши расширяющиеся преобразования охватываются первыми двумя точками выше. Я включил третью точку для завершения, поскольку она охватывает такие вещи, как преобразование из uint32_t
в int32_t
или unsigned int
в long
, где они имеют одинаковую ширину (оба имеют минимальный диапазон но не требуется, чтобы unsigned int
был "тоньше", чем long
).
(a) Это может отличаться в представлениях дополнения или величины знака но, поскольку они находятся в процессе удаления, на самом деле это никого не волнует.
См .:
для более подробной информации.
В любом случае фиксированная ширина типов являются дополнением two, так что вам не нужно беспокоиться об этом аспекте для примера кода.