В чем разница между 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не добавляет новую строку).


Каким образом использование printf()будет менее эффективным? Во время выполнения? Во время компиляции?
Франклин

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

33

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


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().


Пожалуйста, добавьте некоторые объяснения к вашему ответу, чтобы другие могли извлечь из него урок - есть ли у вас надежные источники для этого утверждения? Или какие-то причины, чтобы объяснить эту разницу?
Нико Хаас
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.