Потому что некоторые из них используют буферизованный ввод/вывод,
и все они используют расширения из printf.h. То есть используя printf вы не знаете наверняка дёргается-ли где то внутри него переопределённый обработчик формата или преобразования, которые могут быть и не thread-safe.
Может лучше вместо sprintf() использовать snprintf()?
в идеале наверно да, но на практике я обычно выделяю статический char buf[] заведомо большего размера. а с snprintf придется выделять буфер malloc, анализировать что вернул snprintf и в случае если ему не хватило места делать free и malloc с большим размером...
типа:
Вообще в идеале надо анализировать возврат функции snprintf() и если не хватило места в буфере, то завершать приложение с сообщением на консоли «Bla-bla-bla на такие длинные строки мы не рассчитывали».