Очень мало веских причин использовать int * вместо sint *. Существование этих дополнительных типов, скорее всего, связано с историческими причинами обратной совместимости, которые протоколные буферы пытаются поддерживать даже в своих собственных версиях протокола.
Мое лучшее предположение состоит в том, что в самой ранней версии они тупо кодировали отрицательные целые числа в представлении дополнения 2, что требует кодирования varint максимально размера 9 байтов (не считая байта дополнительного типа). Затем они застряли с этой кодировкой, чтобы не сломать старый код и сериализации, которые уже использовали его. Таким образом, им нужно было добавить новый тип кодирования, sint *, чтобы получить лучшую кодировку переменного размера для отрицательных чисел, не нарушая существующий код. То, как дизайнеры не поняли эту проблему с самого начала, совершенно вне меня.
Кодировка varint (без указания типа, для которой требуется еще 1 байт) может кодировать целочисленное значение без знака в следующем количестве байтов:
[0, 2 ^ 7): один байт
[2 ^ 7, 2 ^ 14): два байта
[2 ^ 14, 2 ^ 21): три байта
[2 ^ 21, 2 ^ 28): четыре байта
[2 ^ 28, 2 ^ 35): пять байтов
[2 ^ 35, 2 ^ 42): шесть байтов
[2 ^ 42, 2 ^ 49): семь байтов
[2 ^ 49, 2 ^ 56): восемь байтов
[2 ^ 56, 2 ^ 64): девять байтов
Если вы хотите компактно подобным образом кодировать отрицательные целые числа малой величины, вам потребуется «использовать» один бит для обозначения знака. Вы можете сделать это через явный бит знака (в некоторой зарезервированной позиции) и представление величины. Или вы можете выполнить зигзагообразное кодирование, которое фактически делает то же самое, сдвигая левую величину на 1 бит и вычитая 1 для отрицательных чисел (поэтому младший значащий бит указывает знак: четные числа неотрицательны, вероятные значения отрицательны).
В любом случае, точки пересечения, в которых положительные целые числа требуют больше места, теперь имеют коэффициент 2 раньше:
[0, 2 ^ 6): один байт
[2 ^ 6, 2 ^ 13): два байта
[2 ^ 13, 2 ^ 20): три байта
[2 ^ 20, 2 ^ 27): четыре байта
[2 ^ 27, 2 ^ 34): пять байтов
[2 ^ 34, 2 ^ 41): шесть байтов
[2 ^ 41, 2 ^ 48): семь байтов
[2 ^ 48, 2 ^ 55): восемь байтов
[2 ^ 55, 2 ^ 63): девять байтов
Чтобы использовать случай int * over sint *, отрицательные числа должны быть чрезвычайно редкими, но возможными, и / или наиболее распространенные положительные значения, которые вы ожидаете кодировать, должны упасть прямо вокруг одного из значений среза. указывает на большее кодирование в sint *, а не на int * (например, - 2 ^ 6 против 2 ^ 7, приводящих к 2x размеру кодирования).
В принципе, если у вас будут числа, где некоторые могут быть отрицательными, то по умолчанию используйте sint * вместо int *. int * очень редко будет превосходить и, как правило, даже не будет стоить дополнительной мысли, которую вы должны посвятить оценке того, стоит ли это того или нет, ИМХО.