В C ++ (до 20) целые числа со знаком и без знака разрешено представлять совершенно по-разному. C ++ не требует, чтобы целые числа со знаком были дополнением до двух; реализациям разрешено использовать одно дополнение или другое представление. Единственное требование, которое C ++ предъявляет к знаковым и беззнаковым, заключается в том, что возможно преобразование всех неотрицательных (или прерывистых) знаковых значений в беззнаковые.
И к вашему сведению: ваш код выдает UB за нарушение правила строгого алиасинга (доступ к объекту типа X через указатель на несвязанный объект типа Y). Хотя это несколько распространено в низкоуровневом коде, объектная модель C ++ на самом деле не позволяет этого. Но я отвлекся.
Я поднял все вещи со знаком-против-без знака, потому что GLSL на самом деле определяет представление целых чисел со знаком. В GLSL целое число со знаком является дополнением до двух. Вследствие этого GLSL может определять, как преобразование из всего диапазона значений без знака переходит к знаковым значениям и наоборот, просто сохраняя битовый шаблон значения.
И это именно то, что он делает. Поэтому вместо того, чтобы использовать литейную гимнастику, вы просто делаете преобразование без знака в подпись, так же, как если бы вы использовали метод с плавающей точкой в подпись или что-то еще:
int i = ...
uint j = uint(i);
Это преобразование сохраняет битовый шаблон.
О, и C ++ 20, похоже, тоже получает на борту это .