В чем разница между printf () и put () в C?

176

Я знаю, что вы можете печатать с printf()и puts(). Я также вижу, что printf()позволяет интерполировать переменные и выполнять форматирование.

Это puts()просто примитивная версия printf(). Должно ли оно использоваться для всех возможных printf()без интерполяции строк?

Алекс
источник
48
Просто обратите внимание на использование printf вместо put: никогда, никогда не делайте a, printf(variable)чтобы напечатать строку. Используйте puts(variable)или printf("%s', variable). При использовании строки формата переменной существует угроза безопасности: если переменная может быть записана злоумышленником, он может атаковать программу, используя строки формата.
Zan Lynx

Ответы:

141

putsПроще, printfно помните, что первый автоматически добавляет новую строку. Если это не то, что вы хотите, вы можете использовать fputsсвою строку в stdout или использовать printf.

Михаил Кристофик
источник
8
Я думаю, что также важно упомянуть дополнительные аргументы, которые printf принимает для добавления дополнительных переменных в выводимую строку.
Erutan409
99

(На это указывает комментарий Zan Lynx, но я думаю, что это заслуживает ответа - учитывая, что в принятом ответе это не упоминается).

Существенная разница между puts(mystr);и printf(mystr);заключается в том, что в последнем случае аргумент интерпретируется как строка форматирования . Результат часто будет таким же (за исключением добавленной новой строки), если строка не содержит управляющих символов ( %), но если вы не можете полагаться на это (если mystrэто переменная, а не литерал), вы не должны использовать ее.

Таким образом, вообще опасно - и концептуально неправильно - передавать динамическую строку как один аргумент printf:

  char * myMessage;
  // ... myMessage gets assigned at runtime, unpredictable content
  printf(myMessage);  // <--- WRONG! (what if myMessage contains a '%' char?) 
  puts(myMessage);    // ok
  printf("%s\n",myMessage); // ok, equivalent to the previous, perhaps less efficient

То же самое относится к fputsпротив fprintf(но fputsне добавляет новую строку).

leonbloy
источник
Каким образом использование printf()будет менее эффективным? Во время выполнения? Во время компиляции?
Франклин
10
@franklin во время выполнения, потому что printfнужно проанализировать строку формата. Однако это обычно не имеет значения. Кроме того, умный компилятор мог бы оптимизировать это, и заменить на printfвызов сputs
leonbloy
33

Помимо форматирования, putsвозвращает неотрицательное целое число в случае успеха или EOFнеудачи; while printfвозвращает количество напечатанных символов (не включая завершающий ноль).

echristopherson
источник
16

В простых случаях компилятор преобразует вызовы printf()в вызовы puts().

Например, следующий код будет скомпилирован с кодом сборки, который я покажу далее.

#include <stdio.h>
main() {
    printf("Hello world!");
    return 0;
}
push rbp
mov rbp,rsp
mov edi,str.Helloworld!
call dword imp.puts
mov eax,0x0
pop rbp
ret

В этом примере я использовал GCC версии 4.7.2 и скомпилировал исходный код gcc -o hello hello.c.

Ханну Балк
источник
9
А как насчет новой строки, которая помещает места в стандартный вывод?
Зубергу
1
Должно быть, printf("Hello world!\n");GCC действительно переводит это в пут. Поскольку это старое сообщение, я буду редактировать его сам.
Рафаэль Алмейда
2
Как вы прочитали ассемблерный код после компиляции кода C?
Корай Тугай
3
@KorayTugay: -save-tempsопция для gcc делает это
Schaiba
Вы также можете использовать такой инструмент, как GDB, чтобы разобрать двоичный файл.
Иван Калоянов
10

Правильно, printfможно считать более мощной версией puts. printfобеспечивает возможность форматирования переменных для вывода с помощью спецификаторов формата , таких как %s, %d, %lfи т.д. ...

Джастин этир
источник
10

По моему опыту, printf()тянет больше кода, чем puts()независимо от формата строки.

Если мне не нужно форматирование, я не использую printf. Тем не менее, fwriteдля stdoutработы намного быстрее , чем puts.

static const char my_text[] = "Using fwrite.\n";
fwrite(my_text, 1, sizeof(my_text) - sizeof('\0'), stdout);

Примечание: в комментариях '\ 0' является целочисленной константой. Правильное выражение должно быть таким, sizeof(char)как указано в комментариях.

Томас Мэтьюз
источник
2
«fwrite to stdout работает намного быстрее, чем put» - В чем может быть причина?
Энтони Хэтчкинс
6
@AntonyHatchkins Обычно это не намного быстрее. Однако, put () действительно должен выполнять вызов strlen () каждый раз для вашей строки, тогда как, если размер известен с помощью fwrite (), этого можно избежать. Это в значительной степени единственный реальный вклад в разницу в производительности.
Wiz
8
Этот ответ неверен. '\0'имеет тип int, поэтому на большинстве систем это будет печатать Using fwrit. Если вы хотите напечатать на 1 байт меньше, просто используйте 1. sizeof (char), что, скорее всего, то, что вы намеревались здесь, гарантированно будет 1.
Брэдли Гараган
8
int puts(const char *s);

put () записывает строку s и завершающий символ новой строки в stdout.

int printf(const char *format, ...);

Функция printf () записывает вывод в stdout под управлением строки формата, которая указывает, как последующие аргументы преобразуются для вывода.

Я воспользуюсь этой возможностью, чтобы попросить вас прочитать документацию.

Корай Тугай
источник
5

функция printf () используется для вывода на экран как строк, так и переменных, в то время как функция put () позволяет печатать только строки на вашем экране.

Уэсли Няндика
источник
2

putsэто простой выбор и добавляет новую строку в конце и printfзаписывает вывод отформатированной строки.

Смотрите документацию для puts и для printf.

Я бы порекомендовал использовать только, так printfкак это более согласованно, чем метод переключения, т. Е. Если вы отлаживаете, поиск по всем printfs менее труден, чем putsи printf. В большинстве случаев вы также хотите выводить переменную в своих распечатках, поэтому putsв основном используется в примере кода.

Йохан Энгблом
источник
1

При сравнении puts()и printf(), хотя их потребление памяти почти одинаково, puts()требуется больше времени по сравнению с printf().

Тил
источник
Пожалуйста, добавьте некоторые объяснения к вашему ответу, чтобы другие могли извлечь из него урок - есть ли у вас надежные источники для этого утверждения? Или какие-то причины, чтобы объяснить эту разницу?
Нико Хаас