Для наилучшей производительности обычно требуется встроенная сборка (как некоторые уже заявили).
Но для переносимого C эти функции включают только одно сравнение и не приведение типов (и поэтому я считаю оптимальным):
unsigned saturate_add_uint(unsigned x, unsigned y)
{
if (y>UINT_MAX-x) return UINT_MAX;
return x+y;
}
unsigned short saturate_add_ushort(unsigned short x, unsigned short y)
{
if (y>USHRT_MAX-x) return USHRT_MAX;
return x+y;
}
Как макросы, они становятся:
SATURATE_ADD_UINT(x, y) (((y)>UINT_MAX-(x)) ? UINT_MAX : ((x)+(y)))
SATURATE_ADD_USHORT(x, y) (((y)>SHRT_MAX-(x)) ? USHRT_MAX : ((x)+(y)))
Я оставляю версии для «unsigned long» и «unsigned long long» в качестве упражнения для читателя. ; -)