printf("foo: ");
против
fputs("foo: ", stdout);
Как упоминалось в заголовке, строка не форматируется и не заканчивается на новой строке (поэтому не ставится). Я не уверен насчет накладных расходов и оптимизации, так каково практическое правило в этом случае?
Обновлено: Нормально ли использовать printf с неформатированными строками?
@Someprogrammerdude Я только начинаю и не знаю об этих оптимизациях. Поэтому искал лучшие практики. Тогда я просто остановлюсь на printf и позволю компилятору сделать все остальное. Спасибо.
Эмпирическое правило: «Преждевременная оптимизация — корень всех зол».
Забавно, что printf и fprintf(stdout, обрабатываются оптимизатором по-разному.
@moooeeeep Это был скорее вопрос о том, что использовать для форматирования и неформатирования, а не об оптимизации, но спасибо, узнал и о преждевременной оптимизации.





Как указано в заголовке, строка не форматируется и не закончить на новой строке (чтобы не помещалось). Я не уверен насчет накладных расходов и оптимизация, так каково практическое правило в этом случае?
printf — гораздо более сложная функция, чем fputs. Но обычно время процессора не является основным узким местом при использовании функций ввода-вывода.Но если вы используете fprintf вместо printf, большинство современных компиляторов оптимизируют ваш fprintf до fwrite. Поэтому используйте fprintf вместо printf, если вы хотите, чтобы ваш код был оптимизирован в этом случае.
Вопрос «что лучше» скорее основан на мнениях. Я предпочитаю использовать printf для обеспечения единообразия. Но «золотого правила» в данном случае нет.
void foo(void)
{
fprintf(stdout, "Hello World");
}
void zoo(void)
{
fputs("Hello World", stdout);
}
void bar(void)
{
printf("Hello World");
}
и полученный код:
.LC0:
.string "Hello World"
foo:
mov edx, 11
mov esi, 1
mov edi, OFFSET FLAT:.LC0
mov rcx, QWORD PTR stdout[rip]
jmp fwrite
zoo:
mov edx, 11
mov esi, 1
mov edi, OFFSET FLAT:.LC0
mov rcx, QWORD PTR stdout[rip]
jmp fwrite
bar:
mov edi, OFFSET FLAT:.LC0
xor eax, eax
jmp printf
https://godbolt.org/z/jKboo51br
Кажется, я немного неправильно сформулировал свой вопрос, и все сосредоточились на части оптимизации, о которой я не совсем спрашивал. Я хотел знать, является ли нормальной практикой использование printf для неформатированных строк. Но в любом случае спасибо, я тоже немного узнал обо всех этих оптимизациях.
@GrandeKnight, ты сформулировал это совершенно ясно - накладные расходы и оптимизация.
ЛМАО, а как насчет предыдущей части «Я не уверен». Я понятия не имею об этом и не спрашивал об этом с этой точки зрения. Значит я действительно неправильно выразился.
Каков правильный путь
Оба способа «правильные», оба будут работать одинаково и нормально.
Рассмотрим правила оптимизации. Не оптимизируйте, если в этом нет необходимости. printf("foo: "); совершенно нормально, читаемо, понятно, все знают, что это значит. Оставь это. printf("foo :"); это здорово.
Если вы действительно хотите оптимизировать и действительно заботитесь о скорости, вы можете вызвать fwrite со статически рассчитанными значениями:
fwrite("foo: ", 1, sizeof("foo: ") - 1, stdout);
Но я сомневаюсь, что оптимизация чего-то стоит. Если бы вас действительно заботила скорость, вы бы все равно вызывали функции, специфичные для ОС, например, в Linux у нас есть write или splice или tee или vmsplice или copy_file_range или sendfile.
если использование printf для неформатированных строк является обычной практикой
Давайте возьмем какой-нибудь большой проект и проверим. Анализируя исходный код gcc, можно обнаружить такое количество строк, которые соответствуют fputs буквальной строке:
$ rg -g '*.[ch]' 'fputs\s*\(\s*"[^"]*"' gcc/ | wc -l
263
$ rg -g '*.[ch]' 'fputs\s*\(\s*"[^"]*"' gcc/ | head
gcc/defaults.h: fputs (":\n", (FILE)); \
gcc/defaults.h: fputs (":\n", (FILE)); \
gcc/defaults.h: fputs (", ", STREAM); \
gcc/defaults.h: fputs (", .-", STREAM); \
gcc/config/csky/csky.h: fputs ("\t.comm\t", STREAM); \
gcc/config/csky/csky.h: fputs ("\t.bss\t", (STREAM)); \
gcc/config/xtensa/xtensa.h: fputs ("@pcrel", FILE); \
gcc/config/c6x/c6x.h: fputs ("\t.long ", FILE); \
gcc/config/visium/visium.h: do { assemble_name (STREAM, NAME); fputs (":\n", STREAM); } while (0)
gcc/config/visium/visium.h:( fputs ("\n\t.comm ", (STREAM)),
И столько строк, соответствующих printf, с буквенной строкой и без аргументов:
$ rg -g '*.[ch]' 'printf\s*\(\s*"[^"]*"\);' gcc/ | wc -l
1792
Есть так много строк с printf, в которых нет символов новой строки в строке форматирования:
$ rg -g '*.[ch]' 'printf\s*\(\s*"[^"]*"\);' gcc/ | grep -v '"[^"]*\\n[^"]*"' | wc -l
470
$ rg -g '*.[ch]' 'printf\s*\(\s*"[^"]*"\);' | grep -v '"[^"]*\\n[^"]*"' | head
zlib/contrib/minizip/miniunz.c: printf(" ");
libdecnumber/decNumber.c: if (decNumberIsInfinite(dn)) printf("Infinity");
libdecnumber/decNumber.c: if (dn->bits&DECSNAN) printf("sNaN"); /* signalling NaN */
libdecnumber/decNumber.c: else printf("NaN");
libdecnumber/decNumber.c: printf(" ");
libdecnumber/decNumber.c: printf(":");
libdecnumber/decCommon.c: if ((num->lsd-ub)%3==0 && ub!=num->lsd) printf(" "); /* 4-space */
libdecnumber/decBasic.c: printf("----- div = ");
libdecnumber/decBasic.c: printf("DivQuo:");
libdecnumber/decBasic.c: printf("CoeffbL:");
Эти цифры выглядят достаточно высокими, я бы сказал, что любое является «правильным». Глядя на это, printf("literal") даже больше, чем fputs("literal", anything).
Я не согласен с мнением, что printf("foo: "); — это нормально. Это не нормально, читабельно и понятно. Да, люди могут знать, что это значит, но, ИМХО, с семантической точки зрения это плохая практика. Когда я вижу printf, я предполагаю, что кто-то печатает что-то отформатированное, значение или что-то в этом роде. На мой взгляд, fputs лучше, или для последовательности printf("%s", "foo: ");, или что-то в этом роде.
Кажется, я немного неправильно сформулировал свой вопрос, и все сосредоточились на части оптимизации, о которой я не совсем спрашивал. Я хотел знать, является ли нормальной практикой использование printf для неформатированных строк. Но в любом случае спасибо, я тоже немного узнал обо всех этих оптимизациях.
это должен быть принятый ответ, поскольку он больше устраняет сомнения ОП
@pochopsp вопрос в данном случае не по теме, так как он основан на мнениях
@pschulz Я согласен с вами: известно, что printf назван в честь «форматировать печать», а puts — в честь «поместить строку». И мы можем быть уверены, что какой-то (дополнительный) код будет выполняться в поисках (отсутствующих) printf спецификаторов в строке формата.
В Python print будет на миллионы инструкций больше. Shell echo используется в любое время, но это будет на миллионы инструкций больше. Преждевременная оптимизация здесь является злом, если только вы не нацеливаетесь на микроконтроллер и не профилируете свой код. Аргументом является только правильность, с чем я согласен. Противодействием может быть то, что в настоящее время у нас есть предупреждения компилятора и линтеры для диагностики % без аргументов. Я не вижу веских аргументов в пользу соблюдения одного стиля, поэтому и рекомендую.
какое практическое правило в этом случае?
Лучше отдать предпочтение fputs(), чтобы избежать строк с "%". Возможно, не сегодня, но возможно в будущем.
В противном случае напишите наиболее понятный код — и это зависит от окружающего кода.
Если вы беспокоитесь об оптимизации этой простой вещи, то в этом нет необходимости. Компилятор с включенной оптимизацией может даже распознать вызов
printfи выдать вам вызовfputs. А если нет, то разница будет незначительной и даже неизмеримой.