Вопрос или проблема
Я пытаюсь выводить в консоль, начиная с новой строки, то есть, если предыдущая строка не заканчивалась на \n, то перед выводом данной строки нужно вывести \n.
Я придумал это, и, похоже, это работает нормально.
#include <stdio.h>
bool newLine = true;
void Output(const char* str)
{
while(*str)
{
putchar(*str++);
}
if (*(str-1) == '\n')
{
newLine = true;
}
else
{
newLine = false;
}
}
void OutputN(const char* str)
{
if (!newLine)
{
putchar('\n');
newLine = true;
}
Output(str);
}
int main()
{
for (int i = 0; i < 10; i++) { Output("."); }
OutputN("01");
Output ("23");
Output (""); // тест, чтобы увидеть, работает ли пустая строка
OutputN("45");
Output ("67\n");
Output (""); // тест, чтобы увидеть, работает ли пустая строка после \n
Output ("89");
for (int i = 0; i < 10; i++) { Output("."); }
Output ("\n");
Output(".");
}
Ссылайтесь на этот поток “C puts() без новой строки“, там есть комментарий, который гласит: “Это работает, но может быть довольно неэффективным, если stdout не буферизуется.” он касается многократного вызова putchar в цикле. Я догадываюсь, что это может быть связано с буферизацией и сбросом.
Мой вопрос заключается в том, при каких обстоятельствах это может стать неэффективным и вероятно ли это создаст мне какие-либо проблемы.
Я планирую вызывать этот Output в общем случае вместо fputs(str, stdout);
1 на Raspberry Pi 5, работающем под kdle, и 2 (возможно, более вероятно иметь проблемы с эффективностью) с Raspberry Pi Pico, который передает свой вывод по последовательному порту.
Вместо цикла используйте puts()
, чтобы записать всю строку. Затем проверьте, является ли последний символ новой строкой.
Вы также должны проверить пустую строку и ничего не делать. Ваш код будет обращаться за пределами массива, если строка пустая, что приведет к неопределенному поведению.
void Output(const char* str)
{
if (str[0] == '\0') { // пустая строка
return;
}
puts(str);
newLine = str[strlen(str)-1] == '\n';
}
Ответ или решение
Чтобы обеспечить корректный вывод на консоль с новой строки в зависимости от предыдущего вывода, вы можете оптимизировать свой код, используя функции стандартной библиотеки, такие как puts()
и избегая непосредственного обхода строки с помощью putchar()
. Это позволит улучшить производительность и избежать неопределенного поведения при работе с пустыми строками.
Вот предложенный подход к вашей задаче:
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
bool newLine = true;
void Output(const char* str)
{
if (str == NULL || str[0] == '\0') { // Проверка на пустую строку
return;
}
puts(str); // Используем puts для вывода всей строки сразу.
// Проверка, заканчивается ли строка на символ новой строки
newLine = (str[strlen(str) - 1] == '\n');
}
void OutputN(const char* str)
{
if (!newLine)
{
putchar('\n'); // Вывод новой строки если предыдущее сообщение не заканчивается на \n
newLine = true; // Устанавливаем флаг новой строки
}
Output(str); // Вызываем функцию для вывода строки
}
int main()
{
for (int i = 0; i < 10; i++) { Output("."); }
OutputN("01");
Output("23");
Output(""); // Тест, чтобы посмотреть, что происходит с пустой строкой
OutputN("45");
Output("67\n");
Output(""); // Тест, чтобы убедиться, что пустая строка работает правильно после \n
Output("89");
for (int i = 0; i < 10; i++) { Output("."); }
Output("\n");
Output(".");
}
Объяснение изменений:
- Проверка на пустую строку: Перед выводом строки проверяется, является ли указатель
str
нулевым или строка пустой. Это позволяет избежать обращения к несуществующему элементу массива. - Оптимизация вывода строки: Вместо использования цикла
putchar()
, используетсяputs()
, который более эффективен для вывода строки, так как работает с буферизацией. - Установка флага новой строки: Флаг
newLine
обновляется на основании последнего символа выводимой строки, что позволяет контролировать, нужно ли выводить дополнительный перенос строки перед новым выводом.
Эффективность:
Ваша первоначальная реализация, хотя и работала, могла оказаться неэффективной при использовании в системах, где stdout
не буферизуется, таких как вывод на последовательный порт, как в случае с Raspberry Pi Pico. В таких случаях каждая операция вывода может приводить к задержкам, если используется putchar()
в цикле.
Используя puts()
, вы минимизируете количество вызовов вывода и позволяете системе управлять буферизацией, что делает код более эффективным и может сократить задержки, особенно при работе с последовательным выводом на устройствах, таких как Raspberry Pi.