printf не работает при использовании вложенных циклов в gcc - PullRequest
0 голосов
/ 24 сентября 2018

Работая над проектом на C и gcc, я натолкнулся на что-то довольно странное, чего не могу понять.Следующий код должен вывести значение i, по крайней мере, один раз, но по какой-то причине в Linux и gcc (также g ++) это не так, он просто зависает, ничего не выводя.Примечание printf действительно работает в других сценариях.

#include <stdio.h>

int main() {
    int i;
    int j;
    int z;
    for (i = 0; i < 47966; i++) {
        printf("%d ", i);
        for (j = 0; j < 47966; j++) {
            for (z = 0; z < 47966; z++) {
            }
        }
    }
    return 0;
}

Кто-нибудь сталкивался с этим?Почему это происходит?

Ответы [ 2 ]

0 голосов
/ 25 сентября 2018

Существует только три случая, когда вывод отправляется из буфера на экран:

1: отправляется, когда буфер переполняется.

2: при переводе строкивстречается символ (в терминале с линейной буферизацией).

3: при приближающемся вводе.

В отличие от того, что было сказано @ Mogzol вкомментарии, если бы здесь возникла какая-то проблема с буферизацией, этот простой цикл не сработал бы:

for(i=0;i<47966;i++)
{
    printf(" %d",i);
}

В этом пошаговом примере что-то еще происходит:

СЛУЧАЙ 1:

#include<stdio.h>

int main(void)
{   
    unsigned long int i=47966ull,k;

    for(k=0;k<i;++k)
    {

    }

    return 0;
}

Этот код занимает почти незначительное время для завершения, хотя цикл ничего не делает.

СЛУЧАЙ 2:

#include<stdio.h>

int main(void)
{
    unsigned long int i=47966,k;

    for(i=0;i<47966;i++)
        for(k=0;k<47966;++k)
            {

            }

    return 0;
}

Приведенный выше код почти занимает 9,1 секунд (не считая ошибки) для выполнения бездействия.

CASE 3:

#include<stdio.h>

int main(void)
{   
    unsigned long int i=47966,k,z;

    for(i=0;i<47966;i++)
    {
        printf(" %d",i);
        for(k=0;k<47966;++k)
        {

        }
    }

    return 0;
}

Это, безусловно, работает, начиная с case 1 , мы можем сказать, что для каждого i waВремя печати меньше, следовательно, цифры печатаются в ближайшее время.

Даже для печати этого простого базового кода (вы можете попробовать это) требуется огромное количество времени:

//WRITTEN TO CHECK WHEN DOES THE FIRST OVERFLOW OCCURS
#include<stdio.h>

int main(void)
{
    unsigned long int i=47966,k,z;

    for(i=0;i<47966;i++)
    {
        printf(" %d",i);
        for(k=0;k<47966;++k)
        {
            printf("-");
        }
    }

    return 0;
}

Inв вашем случае это большое время ожидания перед первым переполнением буфера.Я упомянул переполнение, потому что:

  • Даже если ваш терминал настроен на линейный буфер, нет \n для его очистки.
  • Нет входящего ввода.

SOURCE (S): - Что такое с printf (), отправляющим вывод в буфер?

ПРИМЕЧАНИЕ. Игнорировать часть unsigned long - itбыла только из какой-то старой программы, которую я не потрудился изменить.

MAJOR -> Если вы используете fflush(stdout) во внутреннем цикле, вы обнаружите, что это простопроблема синхронизации - отнимает много времени для буферизации всех их от 0 до 47966 , поскольку в буфере будет только одно число между двумя последовательными сбросами.

0 голосов
/ 25 сентября 2018

Вы, вероятно, страдаете от буферизации .

В большинстве случаев более эффективно записывать на устройство большими кусками, а не множеством маленьких.Запись в файловый дескриптор, а printf - запись в stdout, обычно хранится в буфере памяти перед отправкой на фактическое устройство.Этот буфер должен быть «очищен», что означает, что содержимое буфера записывается на устройство.Существует три типа буферизации: небуферизованная, блочная буферизация и линейная буферизация.

stderr обычно не буферизируется, каждая запись в stderr немедленно отправляется на устройство.Это хорошо, потому что вы хотите сразу увидеть информацию об ошибке.

Файлы, как правило, буферизируются в блоках.Записи сохраняются в буфере памяти BUFSIZ и очищаются при достижении буфера или когда файловый дескриптор закрывается либо явно, либо когда процесс завершается.

stdout равен строка буферизована означает, что он имеет буфер, но автоматически сбрасывается, когда видит новую строку или что-то читается из stdin.Это компромисс между удобством использования и производительностью, обычно вы хотите отображать целые строки за раз или когда запрашиваете ввод.

Ваша программа никогда не выводит новую строку, поэтому ваши числа будут оставаться в буфере строкпока буфер не заполнится или процесс не завершится.Поскольку для печати одного целого числа требуется 2 300 737 156 итераций, пройдет некоторое время, прежде чем заполнится буфер.И 110 357 158 424 696 итераций до того, как программа завершится, автоматически сбросит и закроет stdout.Хотя, если вы скомпилируете его с оптимизацией, компилятор распознает внутренние циклы и ничего не делает;тогда ваш код будет выполняться и печататься очень быстро.

Вы можете решить эту проблему, очистив буфер вручную сразу после печати с помощью fflush(stdout).

...