Вопрос

Я знаю, что у cout есть buffer несколько дней назад, и когда я гуглю это, там сказано, что буфер чем-то похож на стек, и получаю выходные данные cout и printf справа налево, затем выводю их (на консоль или в файл) сверху вниз.Вот так,

a = 1; b = 2; c = 3;
cout<<a<<b<<c<<endl;
buffer:|3|2|1|<-   (take “<-” as a poniter)

output:|3|2|<-     (output 1)
        |3|<-       (output 2)
        |<-         (output 3)

Затем я пишу приведенный ниже код,

#include <iostream> 
using namespace std; 
int c = 6;
int f() 
{   
    c+=1; 
    return c; 
} 

int main() 
{ 
     int i = 0; 
     cout <<"i="<<i<<" i++="<<i++<<" i--="<<i--<<endl; 
     i = 0;
     printf("i=%d i++=%d i--=%d\n" , i , i++ ,i-- );

     cout<<f()<<" "<<f()<<" "<<f()<<endl; 
     c = 6;
     printf("%d %d %d\n" , f() , f() ,f() );
     system("pause");
     return 0; 
}

В версии VS2005 вывод выглядит следующим образом

i=0 i++=-1 i--=0
i=0 i++=-1 i--=0
9 8 7
9 8 7

Кажется, что способ стека правильный ~ Однако вчера я прочитал C ++ Primer Plus, и там сказано, что cout работает слева направо, каждый раз возвращая объект (cout), так что "Это функция, которая позволяет вам объединять выходные данные с помощью insertion".Но путь слева направо не может объяснить cout<

Тогда Алнитак скажи мне это, "Тот << operator - это действительно ostream & operator<<(ostream & os, int), так что другой способ написать это:оператор<< ( оператор<< ( оператор<< ( cout, a ), b ), c )",

Если сначала вычисляется самый правильный аргумент, это может быть немного объяснено.

Теперь я запутался в том, как работает буфер cout, кто-нибудь может мне помочь?

Это было полезно?

Решение

Вы смешиваете множество вещей.На сегодняшний день:

  • Детали реализации cout
  • Связанные вызовы
  • Соглашения о вызовах

Попробуйте прочитать о них по отдельности.И не думайте обо всех них сразу.

printf("i=%d i++=%d i--=%d " , i , i++ ,i-- );

Приведенная выше строка вызывает неопределенное поведение.Прочитайте часто задаваемые вопросы 3.2.Обратите внимание, то, что вы наблюдаете, является побочным эффектом соглашения о вызове функции и способа передачи параметров в стеке конкретной реализацией (т.е.твой).Это не гарантирует, что будет таким же, если вы работали на других машинах.

Я думаю, вы путаете порядок вызовов функций с буферизацией.Когда у вас есть cout оператор, за которым следует несколько вставок << на самом деле вы вызываете несколько вызовов функций, один за другим.Итак, если бы вы написали:

cout << 42 << 0;

Это действительно означает:Ты звонишь,

cout = operator<<(cout, 42)

а затем используйте return в другом вызове того же оператора, что и:

cout = operator<<(cout, 0)

То, что вы проверили вышеизложенным, вам ничего не скажет coutвнутреннее представительство.Я предлагаю вам взглянуть на заголовочные файлы, чтобы узнать больше.

Другие советы

Просто в качестве общего совета, никогда не используйте i ++ в той же строке, что и другое использование i или i--.

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

То же самое относится и к этому случаю, который аналогичен фактическому расширению использования вашего cout:

функция 1 ( функция 2 ( foo ), bar );

Компилятор может свободно удалять bar перед вызовом function2 или наоборот.Вы можете гарантировать, что функция 2 вернется, например, до вызова функции 1, но не то, что их аргументы будут вычислены в определенном порядке.

Это становится проблемой, когда вы делаете что-то вроде:

функция 1 ( функция 2 ( i++), i );

У вас нет способа указать, вычисляется ли "i" до или после "i ++", поэтому вы, скорее всего, получите результаты, отличные от ожидаемых, или разные результаты с разными компиляторами или даже разными версиями одного и того же компилятора.

Итог, избегайте заявлений с побочными эффектами.Используйте их только в том случае, если они являются единственным оператором в строке или если вы знаете, что изменяете одну и ту же переменную только один раз.("Строка" означает один оператор плюс точка с запятой.)

То, что вы видите, является неопределенным поведением.

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

В cout буфер можно рассматривать как очередь, так что Алнитак прав.

В дополнение к другим ответам, которые правильно указывают на то, что вы видите неопределенное поведение, я решил упомянуть, что std::cout использует объект типа std::streambuf чтобы выполнить его внутреннюю буферизацию.По сути, это абстрактный класс, который представляет собой буфер (размер зависит от конкретной реализации и может даже быть равен 0 для небуферизованных потоковых буферов).Тот, который для std::cout написан таким образом, что когда он "переполняется", он сбрасывается в стандартный вывод.

На самом деле, вы можете изменить std::streambuf связанный с std::cout (или любой поток, если уж на то пошло).Это часто полезно, если вы хотите сделать что-то умное, например, сделать все std::cout вызовы заканчиваются в файле журнала или что-то в этом роде.

И как дерк джентли сказал вы путаете соглашение о вызовах с другими деталями, они совершенно не связаны с буферизацией std::cout .

Кроме того, парадигмы смешивания выходных данных (printf и cout) зависят от конкретной реализации.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top