← На главную

Хвостовые вызовы в C наконец заработали в gcc и clang

10.08.2026 11:34 · hackernews

Хвостовые вызовы в C — штука относительно новая. Исторически соглашение о вызовах в C было против них: вызываемая функция не убирает со стека то, что положила вызывающая. Объявление может выглядеть как int f(); — без списка аргументов. При этом реальный вызов может передавать n > 0 аргументов, а сама функция принимать m ≤ n параметров. Если бы вызываемая функция сама снимала аргументы, такой код не всегда работал бы. Поэтому вызывающей стороне приходилось убирать аргументы между вызовом и следующим return, а это превращало вызов в уже не хвостовой.

Когда автор смотрел на C-компиляторы в 1994 году, оптимизации хвостовых вызовов для такого использования они не делали. В 2001 году Mark Probst реализовал её в GCC с отдельным соглашением о вызовах. В разделе 6.4 он перечислил ограничения: GCC не справлялся с косвенными вызовами, а они нужны для диспетчеризации в интерпретаторах.

После этого автор за оптимизацией не следил: ему хватало goto * в GCC. Хотя в одном release note упоминались sibcalls, и он думал, что стоит проверить. В прошлом году он прочитал статью про Copy-and-Patch Compilation от Xu и Kjolstad — там используется оптимизация хвостовых вызовов. После этого автор протестировал gcc и clang на тех самых хвостовых вызовах из обсуждаемого материала. Заработало.

Xu и Kjolstad пишут, что используют 100 000 сниппетов кода. А в Gforth их меньше 2000: VM-инструкции, варианты stack caching, статические суперинструкции и так далее. Возможность использовать 100 000 сниппетов открыла бы техники, которые в системе на goto * не применишь — нужно слишком много разных кусков кода. Но в Gforth это ещё не внедрили. Так что автор поздравляет Python-сообщество: они оказались первыми.

Читать оригинал →