Почему printf и sprintf ведут себя по-разному, когда заданы только массивы?

sub do_printf  { printf @_ }
sub do_sprintf { print sprintf @_ }

do_printf("%s\n", "ok");  # prints ok
do_sprintf("%s\n", "ok"); # prints 2

Ответ 1

Из perldoc на sprintf:

В отличие от printf, sprintf не делает что вы, вероятно, имеете в виду при прохождении это массив в качестве вашего первого аргумента. Массив задается скалярным контекстом и вместо использования 0-го элемента массив как формат, Perl будет использовать количество элементов в массиве как формат, который почти никогда полезно.

Ответ 2

sprintf имеет прототип [email protected], а printf имеет прототип @

Ответ 3

См. ответы codeholic и Mark для объяснения того, почему они ведут себя по-другому.

Как обходной путь, просто выполните:

sub do_sprintf { print sprintf(shift, @_) }

Затем

sub do_printf  { printf @_ }
sub do_sprintf { print sprintf(shift, @_) }

do_printf("%s\n", "ok");  # prints ok
do_sprintf("%s\n", "ok2"); # prints ok2

Ответ 4

Они делают разные вещи. Для printf выход - поток; для sprintf вы хотите, чтобы строка была построена. Он обрабатывает форматирование (f) команды печати. Основной целью printf является распечатать значение, которое он создает для потока, но с помощью s (tring) printf (ormat) вы пытаетесь создать строку, а не печатать ее.

printf возвращает количество символов, напечатанных в потоке в качестве обратной связи. Как только символы печатаются в поток, они перешли из логической структуры программы. Между тем, sprintf нужно передать вам строку. Самый удобный способ - это как возвращаемое значение, которое, поскольку оно находится внутри структуры программы, может быть проверено на длину, или содержит ли оно какие-либо "e" или что угодно.

Почему они не должны вести себя по-другому?

Ответ 5

sprintf оценивает массив в скалярном контексте. В вашем массиве два элемента, поэтому он оценивается как "2" (без конечного\n).