Приведение подписано в unsigned и наоборот, расширяя счетчик байтов - PullRequest
0 голосов
/ 24 февраля 2020
uint32_t a = -1;            // 11111111111111111111111111111111
int64_t b = (int64_t) a;    // 0000000000000000000000000000000011111111111111111111111111111111

int32_t c = -1;             // 11111111111111111111111111111111
int64_t d = (int64_t) c;    // 1111111111111111111111111111111111111111111111111111111111111111

Из вышеприведенного наблюдения видно, что имеет значение только исходное значение sign. Т.е. если исходное 32-разрядное число не подписано, приведение его к 64-разрядному значению добавит 0's влево независимо от значения назначения, подписанного или без знака, и;

, если исходное 32-разрядное число подписано и отрицательное, приведение его к 64-битному значению добавит 1's слева от него независимо от значения назначения, подписанного или без знака.

Правильно ли приведенный выше оператор?

1 Ответ

2 голосов
/ 24 февраля 2020

Правильно, исходный операнд определяет это.

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, так что вам не нужно беспокоиться об этом аспекте для примера кода.

...