Pergunta

Eu sei que cout têm tampão há vários dias, e quando eu google-lo, diz-se que o buffer é alguns como uma pilha e obter a saída de cout e printf da direita para a esquerda, em seguida, colocá-los para fora (ao console ou arquivo) de cima para bottem. Assim,

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)

Então eu escrever um código abaixo,

#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; 
}

De acordo com VS2005, a saída é

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

Parece que o caminho pilha é certo ~ No entanto, eu li C ++ Primer Plus ontem, e diz-se que o trabalho cout da esquerda para a direita, cada vez que retornar um objeto (cout), por isso "Esse é o recurso que permite a saída concatenar usando inserção". Mas a partir da esquerda para a direita, não pode explicar cout <

Depois Alnitak me que diga, "O operador << é realmente ostream & operator << (ostream & os, int), então uma outra maneira de escrever este é: operador << (operador << (operador << (cout, a), b), c)",

Se o argumento mais acertada é primeiro avaliada, pode haver alguma explicou.

Agora estou confuso sobre como o trabalho tampão do cout, alguém pode me ajudar?

Foi útil?

Solução

Você está misturando um monte de coisas. Até à data:

  • As modalidades de execução de cout
  • Chained chama
  • Convenções de chamada

Tente ler em cima deles separadamente. E não pense sobre todos eles de uma vez.

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

A linha acima invoca um comportamento indefinido. Leia o FAQ 3,2 . Note, o que você observa é um efeito colateral da convenção de chamada da função e da forma como os parâmetros são passados ??na pilha por um determinado implementação (ou seja, o seu). Esta não é garantido para ser o mesmo se estivesse a trabalhar em outras máquinas.

Eu acho que você está confundindo a ordem das chamadas de função com buffering. Quando você tem uma declaração cout seguido por várias inserções << na verdade você está invocando várias chamadas de função, um após o outro. Então, se você fosse escrever:

cout << 42 << 0;

que realmente significa: Você chama,

cout = operator<<(cout, 42)

e, em seguida, usar o retorno em outra chamada para o mesmo operador:

cout = operator<<(cout, 0)

O que você testou pela acima não irá dizer-lhe representação interna nada de cout. Eu sugiro que você dê uma olhada os arquivos de cabeçalho para saber mais.

Outras dicas

Assim como uma dica geral, nunca use i ++ na mesma linha que outro uso de i ou i -.

O problema é que os argumentos da função pode ser avaliado em qualquer ordem, por isso, se os seus argumentos de função tem quaisquer efeitos secundários (como o incremento e operações de decremento) você não pode garantir que eles vão operar na ordem que você espera. Isso é algo a evitar.

O mesmo vale para este caso, que é semelhante à expansão real de seu uso cout:

function1 (function2 (foo), barra);

O compilador é livre para bar evaulate antes de chamar function2, ou vice-versa. Você pode garantir que function2 retornará antes function1 é chamado, por exemplo, mas não que os seus argumentos são avaliados em uma ordem específica.

Isso se torna um problema quando você faz algo como:

function1 (function2 (i ++), i);

Você não tem nenhuma maneira de especificar se o "i" é avaliada antes ou depois do "i ++", por isso é provável que você obter resultados que são diferentes do que o esperado, ou resultados diferentes com diferentes compiladores ou mesmo versões diferentes o mesmo compilador.

A linha inferior, declarações evitar com efeitos colaterais. usá-los somente se eles são a única declaração na linha ou se você sabe que você está modificando apenas a mesma variável uma vez. (A "linha" significa uma única instrução mais ponto e vírgula.)

O que você vê é um comportamento indefinido.

i local e c mundial são adicionados / subtraídos várias vezes sem ponto sequência. Isto significa que os valores que você começa pode ser sobre qualquer coisa. Depende do compilador, possivelmente, também a arquitetura do processador e do número de núcleos.

O buffer cout pode ser pensado como fila, para Alnitak é certo.

Além das outras respostas que apontam corretamente que você está vendo um comportamento indefinido, eu percebi que eu mencionar que std::cout usa um objeto do tipo std::streambuf para fazer o seu buffer interno. Basicamente é uma classe abstracta que representa de tampão (o tamanho é determinado de aplicação e pode até mesmo ser 0 para buffers de fluxo unbufferd). A um para std::cout é escrito de tal forma que quando se "transborda" é liberado em stdout.

Na verdade, você pode mudar o std::streambuf associado com std::cout (ou qualquer fluxo para que o assunto). Isso muitas vezes útil se você quiser fazer algo inteligente como fazer todas as chamadas std::cout terminar em um arquivo de log ou algo assim.

E, como disse dirkgently você está confundindo convenção de chamada com outros detalhes, eles são totalmente alheios ao buffer de std :: cout.

Além disso, misturando paradigmas de saída (printf e cout) são implementação específica.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top