Компиляция с TCC на Cygwin

Я тестировал очень простую программу, написанную на C, полная версия которой приведена ниже. При попытке выполнить исполняемый файл, созданный TCC, я заметил, что мне нужно было вводить ввод для каждого последующего вызова fgets() до того, как я действительно увижу вывод любых вызовов printf().

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

Однако я заметил, что если я скомпилирую программу с помощью GCC, она будет нормально работать на терминале, скомпилированном в Cygwin (mintty, хотя я получил те же результаты с rxvt).

Может ли кто-нибудь объяснить, почему это происходит, и как я могу предотвратить это? Я хотел бы компилировать свои программы независимо от Cygwin, но при этом использовать терминал на основе Cygwin.

Спасибо!

int main()
{
        char something[12];

        printf("This printf() should be outputted before you are prompted for input: ");

        fgets(something, sizeof something, stdin);

        printf("You entered, %s", something);
}

person Jonathan Chan    schedule 23.04.2011    source источник


Ответы (3)


Mintty и rxvt — это эмуляторы терминала, основанные на псевдотерминальных устройствах Unix. Cygwin реализует их на основе каналов Windows.

Когда вы компилируете программу с помощью Cygwin gcc, она связывается с Cygwin DLL, которая содержит всю магию для того, чтобы заставить потоки, подключенные к терминалу, работать так, как они должны работать в системе Unix, что означает буферизацию строк по умолчанию.

Однако, когда вы компилируете программу с помощью tcc, вы создаете собственную программу Windows, которая видит только базовые каналы Windows. В библиотеке Microsoft C потоки, подключенные к каналам, по умолчанию полностью буферизованы, поэтому помогает явная очистка с помощью fflush(stdout) или отключение буферизации с помощью setvbuf(stdout, NULL, _IONBF, 0). Библиотека MS C не поддерживает буферизацию строк.

person ak2    schedule 23.04.2011
comment
Из всех ответов я подумал, что у этого было самое подробное объяснение, поэтому я выбрал его как лучший ответ. Спасибо всем! - person Jonathan Chan; 24.04.2011

Это связано с буферизацией стандартного ввода и стандартного вывода. Я не уверен, что стандарт C должен сказать об этом (в C++ потоки привязаны по умолчанию), но вы можете самостоятельно очистить стандартный вывод:

 fflush( stdout );

после вызова printf.

person Community    schedule 23.04.2011

Стандартный поток вывода обычно буферизуется строкой, т. е. буфер сбрасывается, когда вы печатаете новую строку.

Вы можете сбросить его явно с помощью:

fflush(stdout);

И вы можете отключить буферизацию для данного потока s с помощью:

setvbuf(s, NULL, _IONBF, 0);

Дополнительные сведения см. на справочной странице setvbuf().

person Philip    schedule 23.04.2011
comment
По умолчанию stdout буферизуется строкой при отправке на терминал и полностью буферизуется при отправке в другое место (канал, сокет, файл и т. д.). Для сравнения, stderr по умолчанию не буферизуется (поскольку он используется для записи информации, которая может диагностировать почему происходит сбой, возможно до автоматической очистки буферов). - person Donal Fellows; 23.04.2011
comment
@Donal Да, это то, что говорит стандарт, и это также то, что реализует Cygwin, но не библиотека Microsoft C. Там и stdout, и stderr не буферизуются при подключении к консоли и полностью буферизуются при подключении к файлу или каналу. Буферизация строк не поддерживается. - person ak2; 23.04.2011
comment
@ ak2: Вот почему я не предлагал это как решение. Неудивительно, что MS перетряхивает еще одну часть библиотеки C… - person Donal Fellows; 24.04.2011