TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.37K subscribers
Post #1048 4.38K
​​sync_with_stdio
#опытным

std::cout, std::cerr и std::cin - стандартные объекты потоков для работы с вводом-выводом в С++.

Но из С++ программы мы также можем вызывать и сишное апи для работы с IO. Например scanf, printf. Они также могут читать из консоли и писать в нее.

Но как связаны С++ и С апи для работы с IO? Мешают ли они друг другу и скремблят результаты операций? Или все хитрее?

Все хитрее)

И разбирать все будем на примере потока вывода std::cout, для других все аналогично, просто так нагляднее будет.

В базовой конфигурации std::cout и запись в stdout с помощью С апи синхронизированы. То есть следующие вызовы полностью эквивалентны(c- символьная переменная):

std::fputc(stdout, c);
// and
std::cout.rdbuf()->sputc(c);


Запись символа в буфер С++ объекта имеет тот же эффект, что и запись символа в буфер С потока.

На практике это означает, что синхронизированные потоки C++ не буферизуются, и каждая операция ввода-вывода на потоке C++ немедленно применяется к буферу соответствующего потока C. Это позволяет свободно смешивать C++ и C I/O операции.

Обращу внимание. Мы до сих пор говорим только об одном символе. И не спроста: для записи конкретного символа гарантируется синхронизация и потокобезопасность(thread-safety). Но записи в stdout из разных тредов могут перемешивать символы этих записей.

То есть при вызове:

std::cout << "Hello, World!" << std::endl;


по сути имплементация посимвольно записывает приветствие миру в stdout в цикле, вызывая std::putc(stdout, c). Обычно такие функции(типа putc) реализованы с помощью внутренних механизмов синхронизации, обеспечивая потокобезопасность.

И это предательски медленно! Поэтому дефолтные операции ввода-вывода в С++ такие медленные.

Синхронизируют запись каждого символа только трусы! Но мы-то с вами не трусы.

Можно отвязать С++ потоки от С потоков и сделать их независимыми.
Тогда у С++ потоков появляется свой буфер, который работает оптимальнее, чем посимвольная запись. Это может дать сильный буст к производительности стандартных IO операций и по скорости они могут сравниться с сишными.

Чтобы отвязать потоки нужно самой первой строчкой main вызывать следующую функцию. Например так

int main()
{
std::ios::sync_with_stdio(false);
std::cout << "a\n";
std::printf("b\n");
std::cout << "c\n";
}


Вывод может изменяться в разных ситуациях, но вот здесь получился такой вывод:

a
c
b


Видно, что разное апи работает независимо и непоследовательно.

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

Be fast. Stay cool.

#cppcore #optimization #goodoldc #compiler
  • ❤ 24
  • 🔥 12
  • 👍 8
  • 🤔 5
More from @grokaemcpp
  1. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  2. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  3. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  4. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  5. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
  6. Sep 25, 2026​​std::spanstream #опытным Радостная весть для всех, кто пользуется iostreams! В C++23 доб…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →