В чем разница между 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.