'printf' vs. 'cout' в С++
Ответ 1
Я удивлен, что все в этом вопросе утверждают, что std::cout
намного лучше, чем printf
, даже если вопрос просто попросил разницы. Теперь есть разница - std::cout
- это С++, а printf
- C (однако вы можете использовать его на С++, как и все, что угодно от C). Теперь, я буду честен здесь; как printf
, так и std::cout
имеют свои преимущества.
Отказ от ответственности: я более опытен с C, чем С++, поэтому, если есть проблема с моим ответом, не стесняйтесь редактировать или комментировать.
Реальные различия
расширяемость
std::cout
является расширяемым. Я знаю, что люди скажут, что printf
также расширяется, но такое расширение не упоминается в стандарте C (поэтому вам придется использовать нестандартные функции, но не существует общей нестандартной функции), и такие расширения являются одной буквой (поэтому легко конфликтует с уже существующим форматом).
В отличие от printf
, std::cout
полностью зависит от перегрузки оператора, поэтому нет проблем с пользовательскими форматами - все, что вы делаете, это определение подпрограммы, принимающей std::ostream
как первый аргумент, а ваш тип - второй. Таким образом, нет проблем с пространством имен, поскольку у вас есть класс (который не ограничивается одним символом), вы можете иметь для него перегрузку std::ostream
.
Однако я сомневаюсь, что многие люди захотят расширить ostream
(честно говоря, я редко видел такие расширения, даже если их легко сделать). Однако, здесь, если вам это нужно.
Синтаксис
Как легко заметить, оба printf
и std::cout
используют разные синтаксисы. printf
использует стандартный синтаксис функций, используя строки шаблонов и списки аргументов переменной длины. На самом деле, printf
- причина, по которой C имеет их - форматы printf
слишком сложны, чтобы их можно было использовать без них. Однако std::cout
использует другой API - API operator <<
, который возвращает себя.
Как правило, это означает, что версия C будет короче, но в большинстве случаев это не имеет значения. Разница заметна, когда вы печатаете много аргументов. Если вам нужно написать что-то вроде Error 2: File not found.
, считая номер ошибки, и его описание будет заполнителем, код будет выглядеть так. Оба примера работают тождественно (ну, вроде, std::endl
на самом деле сбрасывает буфер).
printf("Error %d: %s.\n", id, errors[id]);
std::cout << "Error " << id << ": " << errors[id] << "." << std::endl;
Хотя это не кажется слишком сумасшедшим (это всего в два раза больше), все становится более сумасшедшим, когда вы на самом деле форматируете аргументы, а не просто печатаете их. Например, печать чего-то типа 0x0424
просто сумасшедшая. Это вызвано состоянием смешивания std::cout
и фактическими значениями. Я никогда не видел языка, где нечто вроде std::setfill
было бы типом (отличным от С++, конечно). printf
четко разделяет аргументы и фактический тип. Я бы предпочел сохранить версию printf
(даже если она выглядит как загадочная) по сравнению с ее версией iostream
(поскольку она содержит слишком много шума).
printf("0x%04x\n", 0x424);
std::cout << "0x" << std::hex << std::setfill('0') << std::setw(4) << 0x424 << std::endl;
Перевод
Здесь находится реальное преимущество printf
. Строка формата printf
хорошо... строка. Это делает его очень легко переводить по сравнению с operator <<
злоупотреблением iostream
. Предполагая, что функция gettext()
преобразуется, и вы хотите показать Error 2: File not found.
, код, который должен получить перевод ранее показанной строки формата, будет выглядеть так:
printf(gettext("Error %d: %s.\n"), id, errors[id]);
Теперь предположим, что мы переводим на Fictionish, где номер ошибки после описания. Переведенная строка будет выглядеть как %2$s oru %1$d.\n
. Теперь, как это сделать на С++? Ну, я понятия не имею. Думаю, вы можете сделать фальшивый iostream
, который строит printf
, который вы можете передать в gettext
или что-то еще для перевода. Конечно, $
не является стандартом C, но он настолько распространен, что он безопасен для использования по моему мнению.
Не нужно запоминать/искать специальный синтаксис целочисленного типа
C имеет множество целочисленных типов, а также С++. std::cout
обрабатывает все типы для вас, а printf
требует определенного синтаксиса в зависимости от целочисленного типа (существуют нецелые типы, но единственным нецеловым типом, который вы будете использовать на практике с printf
, является const char *
( C, можно получить с помощью метода to_c
std::string
)). Например, для печати size_t
вам нужно использовать %zd
, а для int64_t
потребуется использовать %"PRIu64"d
. Таблицы доступны в http://en.cppreference.com/w/cpp/io/c/fprintf и http://en.cppreference.com/w/cpp/types/integer.
Вы не можете напечатать байт NUL, \0
Поскольку printf
использует строки C, а не строки С++, он не может печатать NUL-байт без конкретных трюков. В некоторых случаях в качестве аргумента можно использовать %c
с '\0'
, хотя это явно хак.
Различия, которые никто не заботится о
Производительность
Обновление. Оказывается, что iostream
настолько медленный, что он обычно медленнее вашего жесткого диска (если вы перенаправляете свою программу в файл). Отключение синхронизации с stdio
может помочь, если вам нужно вывести большое количество данных. Если производительность является реальной проблемой (в отличие от написания нескольких строк в STDOUT), просто используйте printf
.
Все думают, что они заботятся о производительности, но никто не мешает ее измерять. Мой ответ заключается в том, что ввод-вывод является узким местом в любом случае, независимо от того, используете ли вы printf
или iostream
. Я думаю, что printf
может быть быстрее, чем быстрый просмотр сборки (скомпилированный с помощью clang с использованием опции -O3
компилятора). Предполагая, что пример моей ошибки, printf
пример делает меньше вызовов, чем пример cout
. Это int main
с printf
:
main: @ @main
@ BB#0:
push {lr}
ldr r0, .LCPI0_0
ldr r2, .LCPI0_1
mov r1, #2
bl printf
mov r0, #0
pop {lr}
mov pc, lr
.align 2
@ BB#1:
Вы можете легко заметить, что две строки и 2
(число) выставляются как аргументы printf
. Это об этом; нет ничего другого. Для сравнения это iostream
скомпилировано для сборки. Нет, нет вставки; каждый вызов operator <<
означает другой вызов с другим набором аргументов.
main: @ @main
@ BB#0:
push {r4, r5, lr}
ldr r4, .LCPI0_0
ldr r1, .LCPI0_1
mov r2, #6
mov r3, #0
mov r0, r4
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
mov r0, r4
mov r1, #2
bl _ZNSolsEi
ldr r1, .LCPI0_2
mov r2, #2
mov r3, #0
mov r4, r0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr r1, .LCPI0_3
mov r0, r4
mov r2, #14
mov r3, #0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr r1, .LCPI0_4
mov r0, r4
mov r2, #1
mov r3, #0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr r0, [r4]
sub r0, r0, #24
ldr r0, [r0]
add r0, r0, r4
ldr r5, [r0, #240]
cmp r5, #0
beq .LBB0_5
@ BB#1: @ %_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit
ldrb r0, [r5, #28]
cmp r0, #0
beq .LBB0_3
@ BB#2:
ldrb r0, [r5, #39]
b .LBB0_4
.LBB0_3:
mov r0, r5
bl _ZNKSt5ctypeIcE13_M_widen_initEv
ldr r0, [r5]
mov r1, #10
ldr r2, [r0, #24]
mov r0, r5
mov lr, pc
mov pc, r2
.LBB0_4: @ %_ZNKSt5ctypeIcE5widenEc.exit
lsl r0, r0, #24
asr r1, r0, #24
mov r0, r4
bl _ZNSo3putEc
bl _ZNSo5flushEv
mov r0, #0
pop {r4, r5, lr}
mov pc, lr
.LBB0_5:
bl _ZSt16__throw_bad_castv
.align 2
@ BB#6:
Однако, честно говоря, это ничего не значит, так как I/O является узким местом в любом случае. Я просто хотел показать, что iostream
не быстрее, потому что он "type safe". Большинство реализаций C реализуют форматы printf
с использованием вычисленного goto, поэтому printf
работает так быстро, даже если компилятор не знает о printf
(а не о том, что это не так), некоторые компиляторы могут оптимизировать printf
в в некоторых случаях - постоянная строка, заканчивающаяся на \n
, обычно оптимизируется до puts
).
Наследование
Я не знаю, почему вы хотели бы наследовать ostream
, но мне все равно. Возможно также с помощью FILE
.
class MyFile : public FILE {}
Тип безопасности
Правда, списки аргументов переменной длины не имеют безопасности, но это не имеет значения, поскольку популярные компиляторы C могут обнаруживать проблемы с строкой формата printf
, если вы включаете предупреждения. Фактически, Clang может сделать это без включения предупреждений.
$ cat safety.c
#include <stdio.h>
int main(void) {
printf("String: %s\n", 42);
return 0;
}
$ clang safety.c
safety.c:4:28: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
printf("String: %s\n", 42);
~~ ^~
%d
1 warning generated.
$ gcc -Wall safety.c
safety.c: In function ‘main’:
safety.c:4:5: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
printf("String: %s\n", 42);
^
$ cat safety.c
#include <stdio.h>
int main(void) {
printf("String: %s\n", 42);
return 0;
}
$ clang safety.c
safety.c:4:28: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
printf("String: %s\n", 42);
~~ ^~
%d
1 warning generated.
$ gcc -Wall safety.c
safety.c: In function ‘main’:
safety.c:4:5: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
printf("String: %s\n", 42);
^
Ответ 2
Из Часто задаваемые вопросы по С++:
[15.1] Почему я должен использовать
<iostream>
вместо традиционного<cstdio>
?Повысьте безопасность типов, уменьшите ошибки, разрешите расширяемость и обеспечивайте наследование.
printf()
, возможно, не сломан, иscanf()
, возможно, пригодный для жизни, несмотря на то, что он подвержен ошибкам, однако оба ограничены в отношении того, что может делать С++ I/O. С++ I/O (с использованием<<
и>>
) относится к C (используяprintf()
иscanf()
):
- Более безопасный тип: с
<iostream>
тип объекта, который является I/O'd, является известный статически компилятором. В контраст,<cstdio>
использует поля "%" для динамически описывают типы.- Меньше ошибок: с
<iostream>
нет избыточных Знаки "%" , которые должны быть согласованы с фактическими объектами, являющимися I/O'd. Удаление избыточности удаляет класс ошибок.- Расширяемость: механизм С++
<iostream>
позволяет создавать новые пользовательские типы для ввода/вывода без разрыва существующий код. Представьте себе хаос, если каждый одновременно добавлял новые несовместимые поля "%" дляprintf()
иscanf()
?!- Inheritable: механизм С++
<iostream>
построен из реальных классов таких какstd::ostream
иstd::istream
. В отличие от<cstdio>
'sFILE*
, это реальные классы и следовательно, наследуемый. Это означает, что вы можете имеют другие определяемые пользователем вещи, которые смотреть и действовать как потоки, но это делать что-то странное и замечательное вещи, которые вы хотите. Вы автоматически использовать циллионы линий Код ввода/вывода, написанный пользователями, которых вы не используете даже знать, и им не нужно знать о вашем "расширенном потоке" класс.
С другой стороны, printf
значительно быстрее, что может оправдывать его использование в предпочтении cout
в очень специфических и ограниченных случаях. Всегда сначала профиль. (См., Например, http://programming-designs.com/2009/02/c-speed-test-part-2-printf-vs-cout/)
Ответ 3
И я quote:
В условиях высокого уровня основными отличиями являются безопасность типов (cstdio не имеет его), производительность (большинство реализаций iostreams медленнее, чем у cstdio) и расширяемость (iostreams позволяет пользовательские выходные цели и бесшовный вывод определенных пользователем типов).
Ответ 4
Люди часто утверждают, что printf
намного быстрее. Это в значительной степени миф. Я только что протестировал его, со следующими результатами:
cout with only endl 1461.310252 ms
cout with only '\n' 343.080217 ms
printf with only '\n' 90.295948 ms
cout with string constant and endl 1892.975381 ms
cout with string constant and '\n' 416.123446 ms
printf with string constant and '\n' 472.073070 ms
cout with some stuff and endl 3496.489748 ms
cout with some stuff and '\n' 2638.272046 ms
printf with some stuff and '\n' 2520.318314 ms
Заключение: если вы хотите использовать только символы новой строки, используйте printf
; в противном случае cout
будет почти таким же быстрым или даже быстрее. Более подробную информацию можно найти на в моем блоге.
Чтобы быть ясным, я не пытаюсь сказать, что iostream
всегда лучше, чем printf
; Я просто пытаюсь сказать, что вы должны принять обоснованное решение на основе реальных данных, а не дикое предположение, основанное на некотором распространенном, вводящем в заблуждение предположении.
Обновление: здесь полный код, который я использовал для тестирования. Скомпилирован с g++
без каких-либо дополнительных параметров (кроме -lrt
для синхронизации).
#include <stdio.h>
#include <iostream>
#include <ctime>
class TimedSection {
char const *d_name;
timespec d_start;
public:
TimedSection(char const *name) :
d_name(name)
{
clock_gettime(CLOCK_REALTIME, &d_start);
}
~TimedSection() {
timespec end;
clock_gettime(CLOCK_REALTIME, &end);
double duration = 1e3 * (end.tv_sec - d_start.tv_sec) +
1e-6 * (end.tv_nsec - d_start.tv_nsec);
std::cerr << d_name << '\t' << std::fixed << duration << " ms\n";
}
};
int main() {
const int iters = 10000000;
char const *text = "01234567890123456789";
{
TimedSection s("cout with only endl");
for (int i = 0; i < iters; ++i)
std::cout << std::endl;
}
{
TimedSection s("cout with only '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << '\n';
}
{
TimedSection s("printf with only '\\n'");
for (int i = 0; i < iters; ++i)
printf("\n");
}
{
TimedSection s("cout with string constant and endl");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789" << std::endl;
}
{
TimedSection s("cout with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789\n";
}
{
TimedSection s("printf with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
printf("01234567890123456789\n");
}
{
TimedSection s("cout with some stuff and endl");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << std::endl;
}
{
TimedSection s("cout with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << '\n';
}
{
TimedSection s("printf with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
printf("%s01234567890123456789%i\n", text, i);
}
}
Ответ 5
One - это функция, которая печатает на stdout. Другой объект, который предоставляет несколько функций-членов и перегрузки operator<<
, которые печатаются в stdout. Есть еще много различий, которые я мог бы перечислить, но я не уверен, что вы после.
Ответ 6
Для меня настоящие различия, которые заставили бы меня перейти на "cout", а не "printf", следующие:
1) < оператор может быть перегружен для моих классов.
2) Выходной поток для cout можно легко изменить в файл: (: copy paste:)
#include <iostream>
#include <fstream>
using namespace std;
int main ()
{
cout << "This is sent to prompt" << endl;
ofstream file;
file.open ("test.txt");
streambuf* sbuf = cout.rdbuf();
cout.rdbuf(file.rdbuf());
cout << "This is sent to file" << endl;
cout.rdbuf(sbuf);
cout << "This is also sent to prompt" << endl;
return 0;
}
3) Я нахожу cout более читаемым, особенно когда у нас много параметров.
Одна проблема с cout
- это параметры форматирования. Форматирование данных (точность, справедливость и т.д.) В printf
проще.
Ответ 7
Две точки, не упомянутые здесь иначе, я нахожу значительными:
1) cout
несет много багажа, если вы еще не используете STL. Он добавляет в ваш объектный файл более чем вдвое больше кода printf
. Это также верно для string
, и это основная причина, по которой я склонен использовать свою собственную библиотеку строк.
2) cout
использует перегруженные операторы <<
, которые я нахожу неудачными. Это может добавить путаницу, если вы также используете оператор <<
по своему назначению (сдвиг влево). Мне лично не нравится перегружать операторов для целей, которые касаются их предполагаемого использования.
Итог: я буду использовать cout
(и string
), если я уже использую STL. В противном случае я стараюсь избегать этого.
Ответ 8
С примитивами, вероятно, совершенно не важно, какой из них вы используете. Я говорю, где он получает полезность, когда вы хотите вывести сложные объекты.
Например, если у вас есть класс,
#include <iostream>
#include <cstdlib>
using namespace std;
class Something
{
public:
Something(int x, int y, int z) : a(x), b(y), c(z) { }
int a;
int b;
int c;
friend ostream& operator<<(ostream&, const Something&);
};
ostream& operator<<(ostream& o, const Something& s)
{
o << s.a << ", " << s.b << ", " << s.c;
return o;
}
int main(void)
{
Something s(3, 2, 1);
// output with printf
printf("%i, %i, %i\n", s.a, s.b, s.c);
// output with cout
cout << s << endl;
return 0;
}
Теперь вышеизложенное может показаться не таким замечательным, но предположим, что вы должны выводить это в нескольких местах вашего кода. Не только это, допустим, вы добавляете поле "int d". С помощью cout вам нужно только изменить его в одном месте. Тем не менее, с printf, вам придется изменить его в возможно много мест, и не только это, вы должны напомнить себе, какие из них вывести.
С учетом сказанного, с помощью cout, вы можете сократить много раз, потраченные на обслуживание вашего кода, а не только на то, что если вы повторно используете объект "Что-то" в новом приложении, вам действительно не нужно беспокоиться о выходе.
Ответ 9
Конечно, вы можете написать "что-то" немного лучше, чтобы поддерживать обслуживание:
#include <iostream>
#include <cstdlib>
using namespace std;
class Something
{
public:
Something(int x, int y, int z) : a(x), b(y), c(z) { }
int a;
int b;
int c;
friend ostream& operator<<(ostream&, const Something&);
void print() const { printf("%i, %i, %i\n", a, b, c); }
};
ostream& operator<<(ostream& o, const Something& s)
{
o << s.a << ", " << s.b << ", " << s.c;
return o;
}
int main(void)
{
Something s(3, 2, 1);
// Output with printf
s.print(); // Simple as well, isn't it?
// Output with cout
cout << s << endl;
return 0;
}
И немного расширенный тест cout vs. printf, добавлен тест "double", если кто-то хочет сделать больше тестирования (Visual Studio 2008, версия версии исполняемого файла):
#include <stdio.h>
#include <iostream>
#include <ctime>
class TimedSection {
char const *d_name;
//timespec d_start;
clock_t d_start;
public:
TimedSection(char const *name) :
d_name(name)
{
//clock_gettime(CLOCK_REALTIME, &d_start);
d_start = clock();
}
~TimedSection() {
clock_t end;
//clock_gettime(CLOCK_REALTIME, &end);
end = clock();
double duration = /*1e3 * (end.tv_sec - d_start.tv_sec) +
1e-6 * (end.tv_nsec - d_start.tv_nsec);
*/
(double) (end - d_start) / CLOCKS_PER_SEC;
std::cerr << d_name << '\t' << std::fixed << duration * 1000.0 << " ms\n";
}
};
int main() {
const int iters = 1000000;
char const *text = "01234567890123456789";
{
TimedSection s("cout with only endl");
for (int i = 0; i < iters; ++i)
std::cout << std::endl;
}
{
TimedSection s("cout with only '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << '\n';
}
{
TimedSection s("printf with only '\\n'");
for (int i = 0; i < iters; ++i)
printf("\n");
}
{
TimedSection s("cout with string constant and endl");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789" << std::endl;
}
{
TimedSection s("cout with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789\n";
}
{
TimedSection s("printf with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
printf("01234567890123456789\n");
}
{
TimedSection s("cout with some stuff and endl");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << std::endl;
}
{
TimedSection s("cout with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << '\n';
}
{
TimedSection s("printf with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
printf("%s01234567890123456789%i\n", text, i);
}
{
TimedSection s("cout with formatted double (width & precision once)");
std::cout << std::fixed << std::scientific << std::right << std::showpoint;
std::cout.width(8);
for (int i = 0; i < iters; ++i)
std::cout << text << 8.315 << i << '\n';
}
{
TimedSection s("cout with formatted double (width & precision on each call)");
std::cout << std::fixed << std::scientific << std::right << std::showpoint;
for (int i = 0; i < iters; ++i)
{ std::cout.width(8);
std::cout.precision(3);
std::cout << text << 8.315 << i << '\n';
}
}
{
TimedSection s("printf with formatted double");
for (int i = 0; i < iters; ++i)
printf("%8.3f%i\n", 8.315, i);
}
}
Результат:
cout with only endl 6453.000000 ms
cout with only '\n' 125.000000 ms
printf with only '\n' 156.000000 ms
cout with string constant and endl 6937.000000 ms
cout with string constant and '\n' 1391.000000 ms
printf with string constant and '\n' 3391.000000 ms
cout with some stuff and endl 9672.000000 ms
cout with some stuff and '\n' 7296.000000 ms
printf with some stuff and '\n' 12235.000000 ms
cout with formatted double (width & precision once) 7906.000000 ms
cout with formatted double (width & precision on each call) 9141.000000 ms
printf with formatted double 3312.000000 ms
Ответ 10
Я бы сказал, что отсутствие расширяемости printf
не совсем верно:
В C это правда. Но в C нет реальных классов.
В С++ можно перегрузить оператор рассылки, поэтому, перегружая оператор char*
и используя printf
следующим образом:
Foo bar;
...;
printf("%s",bar);
может быть возможно, если Foo перегрузит хороший оператор. Или, если вы сделали хороший метод. Короче говоря, printf
для меня такой же расширяемый, как cout
.
Технический аргумент, который я вижу для потоков С++ (в общем... не только cout.):
-
типобезопасность. (И, кстати, если я хочу напечатать один
'\n'
, я используюputchar('\n')
... Я не буду использовать ядерную бомбу, чтобы убить насекомое.). -
Проще учиться. (нет "сложных" параметров для изучения, просто для использования операторов
<<
и>>
) -
Работайте с
std::string
(дляprintf
естьstd::string::c_str()
, но дляscanf
?)
Для printf
я вижу:
-
Легче или, по крайней мере, короче (с точки зрения написания символов) сложное форматирование. Гораздо читаем, для меня (вопрос вкуса, я думаю).
-
Лучший контроль над тем, что сделала функция (верните, сколько написанных символов, а также форматировщик
%n
: "Ничего не напечатано. Аргумент должен быть указателем на подписанный int, где количество написанных символов до сих пор хранится." (from printf - С++ Reference) -
Улучшенная возможность отладки. По той же причине, что и последний аргумент.
Мои личные предпочтения относятся к функциям printf
(и scanf
), главным образом потому, что мне нравятся короткие строки, и потому, что я не думаю, что проблемы с типом печати текста действительно трудно избежать.
Единственное, что я осуждаю с помощью функций стиля С, - это то, что std::string
не поддерживается. Нам нужно пройти через char*
, прежде чем передать его printf
(с std::string::c_str()
, если мы хотим прочитать, но как писать?)
Ответ 11
Другие отличия: "printf" возвращает целочисленное значение (равное количеству напечатанных символов), а "cout" ничего не возвращает
А.
cout << "y = " << 7;
не является атомарным.
printf("%s = %d", "y", 7);
является атомным.
cout выполняет typechecking, printf не делает.
Нет эквивалента iostream "% d"
Ответ 12
Я хотел бы указать, что если вы хотите играть с потоками на С++, если вы используете cout
, вы можете получить интересные результаты.
Рассмотрим этот код:
#include <string>
#include <iostream>
#include <thread>
using namespace std;
void task(int taskNum, string msg) {
for (int i = 0; i < 5; ++i) {
cout << "#" << taskNum << ": " << msg << endl;
}
}
int main() {
thread t1(task, 1, "AAA");
thread t2(task, 2, "BBB");
t1.join();
t2.join();
return 0;
}
// g++ ./thread.cpp -o thread.out -ansi -pedantic -pthread -std=c++0x
Теперь результат все перетасовывается. Он также может давать разные результаты, попробуйте выполнить несколько раз:
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
Вы можете использовать printf
, чтобы получить его правильно, или вы можете использовать mutex
.
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
Удачи!
Ответ 13
TL; DR: всегда выполняйте собственные исследования в отношении кода машинного кода , производительности, читабельности и . время, прежде чем доверять случайным комментариям в Интернете, включая этот.
Я не эксперт. Мне просто пришлось подслушать двух сотрудников, говорящих о том, как избежать использования С++ во встроенных системах из-за проблем с производительностью. Ну, достаточно интересно, я сделал тест, основанный на реальной проектной задаче.
В указанной задаче нам пришлось написать некоторый конфиг в ОЗУ. Что-то вроде:
кофе = горячий
нет сахара = нет
молоко = грудь
Mac = AA: BB: CC: DD: EE: FF
Здесь мои тестовые программы (Да, я знаю, что OP задал вопрос о printf(), а не fprintf(). Попробуйте записать суть и, кстати, ссылка OP указывает на fprintf() в любом случае.)
C:
char coffee[10], sugar[10], milk[10];
unsigned char mac[6];
/* Initialize those things here. */
FILE * f = fopen("a.txt", "wt");
fprintf(f, "coffee=%s\nsugar=%s\nmilk=%s\nmac=%02X:%02X:%02X:%02X:%02X:%02X\n", coffee, sugar, milk, mac[0], mac[1],mac[2],mac[3],mac[4],mac[5]);
fclose(f);
Программа на С++:
//Everything else is identical except:
std::ofstream f("a.txt", std::ios::out);
f << "coffee=" << coffee << "\n";
f << "sugar=" << sugar << "\n";
f << "milk=" << milk << "\n";
f << "mac=" << (int)mac[0] << ":"
<< (int)mac[1] << ":"
<< (int)mac[2] << ":"
<< (int)mac[3] << ":"
<< (int)mac[4] << ":"
<< (int)mac[5] << endl;
f.close();
Я сделал все возможное, чтобы полировать их, прежде чем я зациклил их в 100 000 раз. Вот результаты:
C:
real 0m 8.01s
user 0m 2.37s
sys 0m 5.58s
Программа на С++:
real 0m 6.07s
user 0m 3.18s
sys 0m 2.84s
Размер файла объекта:
C - 2,092 bytes
C++ - 3,272 bytes
Заключение: на моей конкретной платформе с очень специфическим процессором, работающим с очень конкретной версией Linux kernel, для запуска которая скомпилирована с очень конкретной версией GCC, чтобы выполнить очень специфическую задачу, я бы сказал, что подход на С++ более подходит, потому что он работает значительно быстрее и обеспечивают гораздо лучшую читаемость. С другой стороны, C предлагает небольшую площадь, на мой взгляд, почти ничего не значит, потому что размер программы не касается нас.
Память, YMMV.
Ответ 14
cout<< "Hello";
printf("%s", "Hello");
Оба используются для печати значений. Они имеют совершенно другой синтаксис. С++ имеет и C, C имеет только printf.
Ответ 15
Я не программист, но я был инженером по человеческим факторам. Я считаю, что язык программирования должен быть легким для изучения, понимания и использования, и для этого требуется, чтобы он имел простую и последовательную лингвистическую структуру. Хотя все языки являются символическими, и поэтому, по своей сути, произвольным, существуют соглашения, а последующие их облегчают изучение и использование языка.
В С++ и других языках существует огромное количество функций, написанных как функция (параметр), синтаксис, который изначально использовался для функциональных отношений в математике в предкомпьютерную эру. printf()
следует за этим синтаксисом, и если авторы С++ хотели создать любой логически отличный метод для чтения и записи файлов, они могли бы просто создать другую функцию с использованием аналогичного синтаксиса.
В Python мы, конечно, можем печатать, используя также довольно стандартный синтаксис object.method
, то есть variablename.print, поскольку переменные являются объектами, а на С++ они не являются.
Я не люблю синтаксис cout, потому что < оператор не соблюдает никаких правил. Это метод или функция, то есть он принимает параметр и что-то делает. Однако он написан так, как если бы это был оператор математического сравнения. Это плохой подход с точки зрения человеческого фактора.
Ответ 16
printf()
является функцией, тогда как cout
является переменной.