Вывод консоли gcc новая строка

Вопрос или проблема

Я пытаюсь выводить в консоль, начиная с новой строки, то есть, если предыдущая строка не заканчивалась на \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(".");
}

Объяснение изменений:

  1. Проверка на пустую строку: Перед выводом строки проверяется, является ли указатель str нулевым или строка пустой. Это позволяет избежать обращения к несуществующему элементу массива.
  2. Оптимизация вывода строки: Вместо использования цикла putchar(), используется puts(), который более эффективен для вывода строки, так как работает с буферизацией.
  3. Установка флага новой строки: Флаг newLine обновляется на основании последнего символа выводимой строки, что позволяет контролировать, нужно ли выводить дополнительный перенос строки перед новым выводом.

Эффективность:

Ваша первоначальная реализация, хотя и работала, могла оказаться неэффективной при использовании в системах, где stdout не буферизуется, таких как вывод на последовательный порт, как в случае с Raspberry Pi Pico. В таких случаях каждая операция вывода может приводить к задержкам, если используется putchar() в цикле.

Используя puts(), вы минимизируете количество вызовов вывода и позволяете системе управлять буферизацией, что делает код более эффективным и может сократить задержки, особенно при работе с последовательным выводом на устройствах, таких как Raspberry Pi.

Оцените материал
Добавить комментарий

Капча загружается...