Яка різниця між printf () і put () у C?


176

Я знаю, що ви можете друкувати за допомогою printf()та puts(). Я також бачу, що printf()дозволяє інтерполювати змінні та робити форматування.

Це puts()просто примітивна версія printf(). Чи слід його використовувати для всіх можливих printf()без стропової інтерполяції?



47
Просто примітка про використання printf замість put: ніколи, ніколи не робимо printf(variable)для друку рядка. Використовуйте puts(variable)або printf("%s', variable). При використанні рядка змінного формату існує ризик безпеки: якщо змінна може бути записана зловмисником, вони можуть атакувати програму, використовуючи рядки формату.
Зан Лінкс

Відповіді:


141

putsпростіше, printfале майте на увазі, що перший автоматично додає новий рядок. Якщо це не те, що ви хочете, ви можете fputsстворити рядок для stdout або використовувати printf.


8
Я думаю, що також важливо згадати додаткові аргументи printf, прийняті для додавання додаткових змінних у вихідний рядок.
Erutan409

99

(На це вказує у коментарі Зана Лінкс, але я думаю, що це заслуговує відповіді - враховуючи, що прийнята відповідь не згадує його).

Істотна відмінність між 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

Те саме стосується і fputsvs fprintf(але fputsне додає новий рядок).


Яким способом використання printf()було б менш ефективним? На час виконання? На час компіляції?
франклін

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

33

Окрім форматування, putsповертає негативне ціле число у разі успіху або у EOFразі невдачі; при цьому 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
А як щодо нової лінії, яка розміщує місця в stdout?
zubergu

1
Це повинен був printf("Hello world!\n");gcc справді перекладати, що ставити. Оскільки це старе повідомлення, я сам його відредагую.
Рафаель Альмейда,

2
Як ви прочитали код складання після складання коду С?
Корай Тугай

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 працює набагато швидше, ніж ставить." - Що може бути причиною?
Антоні Хеткінс

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.