Existe uma diferença de desempenho entre i ++ e ++ i em C?

Respostas:

397

Resumo executivo: Não.

i++pode ser potencialmente mais lento do que ++i, já que o valor antigo de i talvez precise ser salvo para uso posterior, mas na prática todos os compiladores modernos otimizarão isso.

Podemos demonstrar isso observando o código dessa função, com ++ie i++.

$ cat i++.c
extern void g(int i);
void f()
{
    int i;

    for (i = 0; i < 100; i++)
        g(i);

}

Os arquivos são os mesmos, exceto ++ie i++:

$ diff i++.c ++i.c
6c6
<     for (i = 0; i < 100; i++)
---
>     for (i = 0; i < 100; ++i)

Vamos compilá-los e também obter o assembler gerado:

$ gcc -c i++.c ++i.c
$ gcc -S i++.c ++i.c

E podemos ver que o objeto gerado e os arquivos do assembler são os mesmos.

$ md5 i++.s ++i.s
MD5 (i++.s) = 90f620dda862cd0205cd5db1f2c8c06e
MD5 (++i.s) = 90f620dda862cd0205cd5db1f2c8c06e

$ md5 *.o
MD5 (++i.o) = dd3ef1408d3a9e4287facccec53f7d22
MD5 (i++.o) = dd3ef1408d3a9e4287facccec53f7d22
Mark Harrison
fonte
9
Eu sei que esta pergunta é sobre C, mas eu estaria interessado em saber se os navegadores podem fazer essa otimização para javascript.
TM.
69
Portanto, o "Não" é verdadeiro para o compilador que você testou.
Andreas
173
@ Andréas: Boa pergunta. Eu costumava escrever um compilador e tive a oportunidade de testar esse código em muitas CPUs, sistemas operacionais e compiladores. O único compilador que descobri que não otimizou o caso i ++ (de fato, o compilador que chamou minha atenção profissionalmente) foi o compilador Software Toolworks C80 de Walt Bilofsky. Esse compilador era para sistemas Intel 8080 CP / M. É seguro dizer que qualquer compilador que não inclua essa otimização não se destina a uso geral.
Mark Harrison
22
Embora a diferença de desempenho seja insignificante e otimizada em muitos casos - observe que ainda é uma boa prática usar em ++ivez de i++. Não há absolutamente nenhuma razão para não fazê-lo, e se seu software passar por uma cadeia de ferramentas que não a otimiza, seu software será mais eficiente. Considerando que é tão fácil digitar ++iquanto digitar i++, não há realmente desculpa para não usar ++iem primeiro lugar.
monokrome
7
@monokrome Como os desenvolvedores podem fornecer sua própria implementação para os operadores de prefixo e postfix em muitos idiomas, essa nem sempre é uma solução aceitável para um compilador, sem antes comparar as funções, o que pode não ser trivial.
pickypg
112

De eficiência versus intenção de Andrew Koenig:

Primeiro, está longe de ser óbvio que ++ié mais eficiente que i++, pelo menos no que diz respeito a variáveis ​​inteiras.

E:

Portanto, a pergunta que se deve fazer não é qual dessas duas operações é mais rápida, mas qual dessas duas operações expressa com mais precisão o que você está tentando realizar. Sugiro que se você não estiver usando o valor da expressão, nunca há uma razão para usar i++em vez de ++i, porque nunca há uma razão para copiar o valor de uma variável, incrementar a variável, e depois jogar a cópia de distância.

Portanto, se o valor resultante não for usado, eu usaria ++i. Mas não porque é mais eficiente: porque afirma corretamente minha intenção.

Sébastien RoccaSerra
fonte
5
Não vamos esquecer que outros operadores unários também são prefixos. Eu acho que ++ i é a maneira "semântica" de usar um operador unário, enquanto o i ++ existe para atender a uma necessidade específica (avaliação antes da adição).
TM.
9
Se o valor resultante não for usado, não há diferença na semântica: ou seja, não há base para preferir uma ou outra construção.
Eamon Nerbonne
3
Como leitor, vejo uma diferença. Então, como escritor, mostrarei minha intenção escolhendo uma sobre a outra. É apenas um hábito que tenho, para tentar se comunicar com os meus amigos e companheiros de equipe programador através de código :)
Sébastien RoccaSerra
11
Seguindo o conselho de Koenig, eu codifico i++da mesma maneira que codificaria i += nou i = i + n, no formato objeto verbo alvo , com o operando alvo à esquerda do operador verbo . No caso de , não há objeto certo , mas a regra ainda se aplica, mantendo o destino à esquerda do operador do verbo . i++
David R Tribble
4
Se você está tentando incrementar i, i ++ e ++ i expressam corretamente sua intenção. Não há razão para preferir um ao outro. Como leitor, não vejo diferença, seus colegas ficam confusos quando veem o i ++ e pensam: talvez esse seja um erro de digitação e ele não pretenda incrementar o i?
dan carter
46

Uma resposta melhor é que ++iàs vezes será mais rápido, mas nunca mais lento.

Todo mundo parece estar assumindo que esse ié um tipo interno comum, como int. Nesse caso, não haverá diferença mensurável.

No entanto, se ifor do tipo complexo, você poderá encontrar uma diferença mensurável. Pois i++você deve fazer uma cópia da sua classe antes de incrementá-la. Dependendo do que está envolvido em uma cópia, pode ser realmente mais lento, pois ++itvocê pode apenas retornar o valor final.

Foo Foo::operator++()
{
  Foo oldFoo = *this; // copy existing value - could be slow
  // yadda yadda, do increment
  return oldFoo;
}

Outra diferença é que ++ivocê tem a opção de retornar uma referência em vez de um valor. Novamente, dependendo do que estiver envolvido em fazer uma cópia do seu objeto, isso pode ser mais lento.

Um exemplo do mundo real de onde isso pode ocorrer seria o uso de iteradores. É pouco provável que copiar um iterador seja um gargalo no aplicativo, mas ainda é uma boa prática adquirir o hábito de usar em ++ivez de i++onde o resultado não é afetado.

Andrew Grant
fonte
36
A pergunta afirma explicitamente C, sem referência ao C ++.
Dan Cristoloveanu 10/10/08
5
Essa questão (reconhecidamente antiga) era sobre C, não C ++, mas acho que também vale a pena mencionar que, em C ++, mesmo que uma classe implemente operadores de pós e pré-correção, eles não são necessariamente relacionados. Por exemplo, a barra ++ pode incrementar um membro de dados, enquanto a barra ++ pode incrementar um membro de dados diferente e, nesse caso, você também não teria a opção de usar, pois a semântica é diferente.
Kevin
-1 Embora seja um bom conselho para programadores de C ++, ele não responde à pergunta, que é marcada como C, nem um pouco. Em C, absolutamente não faz diferença se você usa prefixo ou postfix.
Lundin
@Pacerier A pergunta está marcada com C e somente C. Por que você acha que eles não estão interessados ​​nisso? Dado como o SO funciona, não seria inteligente supor que eles estão interessados ​​em C, em vez de Java, C #, COBOL ou qualquer outra linguagem fora do tópico?
Lundin
18

Resposta curta:

Nunca há diferença entre i++e ++iem termos de velocidade. Um bom compilador não deve gerar código diferente nos dois casos.

Resposta longa:

O que todas as outras respostas não mencionam é que a diferença entre ++iversus i++só faz sentido na expressão encontrada.

No caso de for(i=0; i<n; i++), o i++está sozinho em sua própria expressão: há um ponto de sequência antes do i++e há um depois dele. Portanto, o único código de máquina gerado é "aumentar iem 1" e está bem definido como isso é sequenciado em relação ao restante do programa. Portanto, se você o alterasse para prefixo ++, não importaria nem um pouco, ainda assim você obteria o código de máquina "aumentar iem 1".

As diferenças entre ++ie i++somente são importantes em expressões como array[i++] = x;versus array[++i] = x;. Alguns podem argumentar e dizer que o postfix será mais lento nessas operações porque o registro em que ireside precisa ser recarregado mais tarde. Mas observe que o compilador é livre para solicitar suas instruções da maneira que desejar, desde que não "quebre o comportamento da máquina abstrata", como o padrão C chama.

Portanto, enquanto você pode assumir que array[i++] = x;é traduzido para o código da máquina como:

  • Armazene o valor ino registro A.
  • Armazene o endereço da matriz no registro B.
  • Adicione A e B, armazene os resultados em A.
  • Nesse novo endereço representado por A, armazene o valor de x.
  • Armazene o valor do iregistrador A // ineficiente porque instruções extras aqui, já fizemos isso uma vez.
  • Registro de incremento A.
  • Armazene o registro A em i.

o compilador também pode produzir o código com mais eficiência, como:

  • Armazene o valor ino registro A.
  • Armazene o endereço da matriz no registro B.
  • Adicione A e B, armazene os resultados em B.
  • Registro de incremento A.
  • Armazene o registro A em i.
  • ... // resto do código.

Só porque você como programador C é treinado para pensar que o postfix ++acontece no final, o código da máquina não precisa ser solicitado dessa maneira.

Portanto, não há diferença entre prefixo e postfix ++em C. Agora, o que você como programador em C deve variar é de pessoas que inconsistentemente usam o prefixo em alguns casos e o postfix em outros casos, sem qualquer justificativa. Isso sugere que eles não sabem ao certo como o C funciona ou que têm conhecimento incorreto do idioma. Esse é sempre um mau sinal, pois sugere que eles estão tomando outras decisões questionáveis ​​em seu programa, com base em superstições ou "dogmas religiosos".

"Prefixo ++é sempre mais rápido" é, de fato, um desses dogmas falsos que é comum entre os possíveis programadores C.

Lundin
fonte
3
Ninguém disse "Prefixo ++ é sempre mais rápido". Isso é citado incorretamente. O que eles disseram foi "O Postfix ++ nunca é mais rápido".
Pacerier 17/02
2
@ Pacerier Não estou citando nenhuma pessoa em particular, mas apenas uma crença ampla e incorreta.
Lundin
@rbaleksandar C ++! = C.
Lundin
@rbaleksandar A pergunta e a resposta falam sobre C ++. Que é diferente do C, uma vez que tem sobrecarga de operadores e construtores de cópia etc.
Lundin
3
@rbaleksandar c ++ == c && ++ c = c!
sadljkfhalskdjfh
17

Tomando uma folha de Scott Meyers, mais eficaz c ++ Item 6: Distinguir entre formas de prefixo e postfix de operações de incremento e decremento .

A versão do prefixo é sempre preferida ao postfix em relação aos objetos, especialmente em relação aos iteradores.

A razão para isso, se você observar o padrão de chamada dos operadores.

// Prefix
Integer& Integer::operator++()
{
    *this += 1;
    return *this;
}

// Postfix
const Integer Integer::operator++(int)
{
    Integer oldValue = *this;
    ++(*this);
    return oldValue;
}

Observando este exemplo, é fácil ver como o operador de prefixo sempre será mais eficiente que o postfix. Por causa da necessidade de um objeto temporário no uso do postfix.

É por isso que, quando você vê exemplos usando iteradores, eles sempre usam a versão do prefixo.

Mas, como você aponta para int, não há efetivamente nenhuma diferença devido à otimização do compilador que pode ocorrer.

JProgrammer
fonte
4
Acho que a pergunta dele foi direcionada para C, mas para C ++ você está absolutamente certo e, além disso, as pessoas em C devem adotar isso, pois também podem usá-lo para C ++. Frequentemente, vejo programadores C usarem a sintaxe do postfix ;-)
Anders Rune Jensen
-1 Embora seja um bom conselho para programadores de C ++, ele não responde à pergunta, que é marcada como C, nem um pouco. Em C, absolutamente não faz diferença se você usa prefixo ou postfix.
Lundin
1
O prefixo @Lundin e o postifx são importantes em C, conforme resposta de Andreas . Você não pode assumir que o compilador será otimizado, e é apenas uma boa prática para qualquer idioma preferir ++ i sobre i ++
JProgrammer
@JProgrammer Eles não importam, de acordo com a resposta da sua sinceridade :) Se você achar que eles produzem código diferente, é porque você falhou em ativar as otimizações ou porque o compilador é ruim. De qualquer forma, a sua resposta é off-topic como a pergunta foi sobre C.
Lundin
16

Aqui está uma observação adicional se você estiver preocupado com a micro otimização. Decrementar loops pode 'possivelmente' ser mais eficiente do que incrementar loops (dependendo da arquitetura do conjunto de instruções, por exemplo, ARM), dado:

for (i = 0; i < 100; i++)

Em cada loop, você terá uma instrução para:

  1. Adicionando 1a i.
  2. Compare se ié menor que a 100.
  3. Uma ramificação condicional se ifor menor que a 100.

Considerando que um loop decrescente:

for (i = 100; i != 0; i--)

O loop terá uma instrução para cada um dos seguintes:

  1. Decremento i, configurando o sinalizador de status do registro da CPU.
  2. Uma ramificação condicional, dependendo do status do registro da CPU ( Z==0).

Obviamente, isso funciona apenas ao diminuir para zero!

Lembrado no Guia do Desenvolvedor do ARM System.

tonylo
fonte
Um bom. Mas isso não cria menos ocorrências de cache?
AndreasT
Existe um velho truque estranho nos livros de otimização de código, combinando a vantagem da ramificação de teste zero com o endereço incrementado. Aqui está um exemplo em linguagem de alto nível (provavelmente inútil, pois muitos compiladores são inteligentes o suficiente para substituí-lo por um código de loop menos eficiente, mas mais comum): int a [N]; para (i = -N; i; ++ i) a [N + i] + = 123;
noop
@noop você poderia elaborar quais livros de otimização de código você se refere? Eu lutei para encontrar bons.
mezamorphic 14/05
7
Esta resposta não é uma resposta para a pergunta.
monokrome
@mezamorphic Para x86, minhas fontes são: manuais de otimização Intel, Agner Fog, Paul Hsieh, Michael Abrash.
noop
11

Por favor, não deixe que a questão de "qual é o mais rápido" seja o fator decisivo a ser utilizado. Provavelmente, você nunca vai se importar tanto e, além disso, o tempo de leitura do programador é muito mais caro que o tempo da máquina.

Use o que fizer mais sentido para o ser humano que lê o código.

Andy Lester
fonte
3
Eu acredito que é errado preferir melhorias vagas de legibilidade a ganhos reais de eficiência e clareza geral de intenção.
noop
4
Meu termo "tempo de leitura do programador" é aproximadamente análogo a "clareza de intenção". Os "ganhos reais de eficiência" costumam ser incomensuráveis, próximos o suficiente para zero para chamá-los de zero. No caso do OP, a menos que o código tenha sido elaborado para descobrir que o ++ i é um gargalo, a questão de qual deles é mais rápido é uma perda de tempo e unidades de pensamento do programador.
Andy Lester
2
A diferença na legibilidade entre ++ i e i ++ é apenas uma questão de preferência pessoal, mas ++ i implica claramente uma operação mais simples que i ++, apesar do resultado ser equivalente para casos triviais e tipos de dados simples ao envolver a otimização do compilador. Portanto, ++ i é um vencedor para mim, quando propriedades específicas de pós-incremento não são necessárias.
noop
Você está dizendo o que estou dizendo. É mais importante mostrar intenção e melhorar a legibilidade do que se preocupar com "eficiência".
Andy Lester
2
Eu ainda não posso concordar. Se a legibilidade estiver mais alta na sua lista de prioridades, talvez a sua escolha de linguagem de programação esteja errada. O objetivo principal do C / C ++ é escrever código eficiente.
noop
11

Primeiro de tudo: a diferença entre i++e ++ié negligenciável em C.


Para os detalhes.

1. O conhecido problema do C ++: ++ié mais rápido

Em C ++, ++ié mais eficiente iff ié algum tipo de objeto com um operador de incremento sobrecarregado.

Por quê?
Em ++i, o objeto é incrementado primeiro e pode ser passado posteriormente como uma referência const para qualquer outra função. Isso não é possível se a expressão for foo(i++)porque agora o incremento precisa ser feito antes da foo()chamada, mas o valor antigo precisa ser passado para foo(). Conseqüentemente, o compilador é forçado a fazer uma cópia iantes de executar o operador de incremento no original. As chamadas adicionais de construtor / destruidor são a parte ruim.

Como observado acima, isso não se aplica a tipos fundamentais.

2. O fato pouco conhecido: i++ pode ser mais rápido

Se nenhum construtor / destruidor precisar ser chamado, o que é sempre o caso em C ++ie i++deve ser igualmente rápido, certo? Não. Eles são virtualmente igualmente rápidos, mas pode haver pequenas diferenças, que a maioria dos respondentes entendeu errado.

Como pode i++ser mais rápido?
O ponto é dependências de dados. Se o valor precisar ser carregado da memória, duas operações subseqüentes precisarão ser feitas com ele, incrementando-o e usando-o. Com ++i, o incremento precisa ser feito antes que o valor possa ser usado. Com i++, o uso não depende do incremento, e a CPU pode executar a operação de uso em paralelo à operação de incremento. A diferença é no máximo um ciclo da CPU, por isso é realmente negligenciável, mas está lá. E é o contrário, então muitos esperariam.

cmaster - restabelece monica
fonte
Sobre o seu ponto 2: Se o ++iou i++for usado em outra expressão, a alteração entre eles altera a semântica da expressão, portanto, qualquer ganho / perda de desempenho possível está fora de questão. Se eles forem autônomos, ou seja, o resultado da operação não for usado imediatamente, qualquer compilador decente irá compilá-lo da mesma maneira, por exemplo, uma INCinstrução de montagem.
Shahbaz
1
@ Shahbaz Isso é perfeitamente verdade, mas não é o ponto. 1) Mesmo que a semântica é diferente, tanto i++e ++ipodem ser usados alternadamente em quase todas as situações possíveis, ajustando constantes loop por um, então eles são equivalente mais próximo no que eles fazem para o programador. 2) Embora ambos sejam compilados com a mesma instrução, sua execução difere para a CPU. No caso de i++, a CPU pode calcular o incremento paralelamente a alguma outra instrução que usa o mesmo valor (as CPUs realmente fazem isso!), Enquanto ++ia CPU precisa agendar a outra instrução após o incremento.
cmaster - reinstala monica em
4
@ Shahbaz Como exemplo: if(++foo == 7) bar();e if(foo++ == 6) bar();são funcionalmente equivalentes. No entanto, o segundo pode ser um ciclo mais rápido, porque a comparação e o incremento podem ser calculados em paralelo pela CPU. Não que esse ciclo único tenha muita importância, mas a diferença está aí.
cmaster - restabelece monica
1
Bom ponto. As constantes aparecem muito (assim como, <por exemplo, vs <=) onde ++é geralmente usado, portanto a conversão entre o pensamento é geralmente possível.
Shahbaz
1
Eu gosto do ponto 2, mas isso só se aplica se o valor for usado, certo? A pergunta diz "se o valor resultante não for usado?", Portanto, pode ser confuso.
jinawee
7

@ Mark Mesmo que o compilador possa otimizar a cópia temporária (baseada em pilha) da variável e o gcc (nas versões recentes) o esteja fazendo, isso não significa que todos os compiladores sempre o farão.

Acabei de testá-lo com os compiladores que usamos em nosso projeto atual e 3 em cada 4 não o otimizam.

Nunca assuma que o compilador esteja certo, especialmente se o código possivelmente mais rápido, mas nunca mais lento, for tão fácil de ler.

Se você não tem uma implementação realmente estúpida de um dos operadores no seu código:

Sempre preferi ++ i sobre i ++.

Andreas
fonte
Apenas curioso ... por que você usa 4 compiladores C diferentes em um projeto? Ou em uma equipe ou uma empresa, para esse assunto?
Lawrence Dol
3
Ao criar jogos para consoles, todas as plataformas trazem seu próprio compilador / conjunto de ferramentas. Em um mundo perfeito, poderíamos usar o gcc / clang / llvm para todos os destinos, mas neste mundo temos que aturar Microsoft, Intel, Metroworks, Sony etc.
Andreas
5

Em C, o compilador geralmente pode otimizá-los para que sejam iguais, se o resultado não for utilizado.

No entanto, em C ++, se estiver usando outros tipos que fornecem seus próprios operadores ++, a versão do prefixo provavelmente será mais rápida que a versão do postfix. Portanto, se você não precisar da semântica do postfix, é melhor usar o operador prefix.

Kristopher Johnson
fonte
4

Posso pensar em uma situação em que o postfix é mais lento que o incremento de prefixo:

Imagine que um processador com registro Aseja usado como acumulador e seja o único registro usado em muitas instruções (alguns microcontroladores pequenos são assim).

Agora imagine o seguinte programa e sua tradução em uma montagem hipotética:

Incremento do prefixo:

a = ++b + c;

; increment b
LD    A, [&b]
INC   A
ST    A, [&b]

; add with c
ADD   A, [&c]

; store in a
ST    A, [&a]

Incremento do Postfix:

a = b++ + c;

; load b
LD    A, [&b]

; add with c
ADD   A, [&c]

; store in a
ST    A, [&a]

; increment b
LD    A, [&b]
INC   A
ST    A, [&b]

Observe como o valor de bfoi forçado a ser recarregado. Com o incremento de prefixo, o compilador pode apenas incrementar o valor e prosseguir com o uso, possivelmente evitar recarregá-lo, pois o valor desejado já está no registro após o incremento. No entanto, com o incremento do postfix, o compilador precisa lidar com dois valores, um antigo e o valor incrementado que, como mostro acima, resulta em mais um acesso à memória.

Obviamente, se o valor do incremento não for usado, como uma única i++;instrução, o compilador pode (e gera) simplesmente gerar uma instrução de incremento, independentemente do uso do postfix ou do prefixo.


Como uma observação lateral, eu gostaria de mencionar que uma expressão na qual existe b++não pode ser simplesmente convertida em uma ++bsem esforço adicional (por exemplo, adicionando a - 1). Portanto, comparar os dois se eles fazem parte de alguma expressão não é realmente válido. Muitas vezes, onde você usa b++dentro de uma expressão que não pode usar ++b, mesmo que ++bfosse potencialmente mais eficiente, isso seria errado. Exceção é claro se a expressão está implorando por ela (por exemplo, a = b++ + 1;que pode ser alterada para a = ++b;).

Shahbaz
fonte
4

Eu tenho lido pela maioria das respostas aqui e muitos dos comentários, e eu não vi qualquer referência à um exemplo que eu poderia pensar de onde i++é mais eficiente do que ++i(e talvez surpreendentemente --i foi mais eficiente do que i--). Isso é para compiladores C para o DEC PDP-11!

O PDP-11 tinha instruções de montagem para pré-decremento de um registro e pós-incremento, mas não o contrário. As instruções permitiram que qualquer registro "de uso geral" fosse usado como ponteiro de pilha. Portanto, se você usasse algo parecido, *(i++)ele poderia ser compilado em uma única instrução de montagem, enquanto *(++i)não poderia.

Este é obviamente um exemplo muito esotérico, mas fornece a exceção em que o pós-incremento é mais eficiente (ou eu deveria dizer que foi , já que não há muita demanda pelo código C do PDP-11 atualmente).

daShier
fonte
2
Muito esotérico, mas muito interessante!
Mark Harrison
@daShier. +1, embora eu discorde, isso não é tão esotérico, ou pelo menos não deveria ser. C foi co-desenvolvido com o Unix na AT&T Bell Labs no início dos anos 70, quando o PDP-11 era o processador alvo. No código-fonte Unix dessa era pós-incremento, "i ++", é mais prevalente em parte porque os desenvolvedores sabiam quando o valor é atribuído "j = i ++" ou usado como índice "a [i ++] = n", o código seria um pouco mais rápido (e menor). Parece que eles adquiriram o hábito de usar o pós-incremento, a menos que o pré seja necessário. Outros aprenderam lendo seu código e também adquiriram esse hábito.
jimhark
O 68000 possui o mesmo recurso: pós-incremento e pré-decremento são suportados no hardware (como modos de endereçamento), mas não o contrário. A equipe da Motorola foi inspirada no DEC PDP-11.
jimhark
2
@ Jimhark, sim, eu sou um daqueles programadores PDP-11 que fizeram a transição para o 68000 e ainda usam --ie i++.
DaShier
2

Eu sempre prefiro pré-incremento, no entanto ...

Queria ressaltar que, mesmo no caso de chamar a função operator ++, o compilador poderá otimizar o temporário se a função for incorporada. Como o operador ++ é geralmente curto e frequentemente implementado no cabeçalho, é provável que ele seja incorporado.

Portanto, para fins práticos, provavelmente não há muita diferença entre o desempenho das duas formas. No entanto, eu sempre prefiro o pré-incremento, pois parece melhor expressar diretamente o que estou tentando dizer, em vez de confiar no otimizador para descobrir isso.

Além disso, dar menos chances ao otimizador significa que o compilador será executado mais rapidamente.


fonte
Sua postagem é específica para C ++, enquanto a pergunta é sobre C. Em qualquer caso, sua resposta está errada: para operadores personalizados pós-incremento, o compilador geralmente não poderá produzir um código eficiente.
Konrad Rudolph
Ele afirma "se a função é incorporada", e isso torna seu raciocínio correto.
Blaisorblade 15/01/09
Como o C não fornece sobrecarga do operador, a pergunta pré vs. pós é amplamente desinteressante. O compilador pode otimizar uma temperatura não utilizada usando a mesma lógica aplicada a qualquer outro valor calculado primitivamente não utilizado. Veja a resposta selecionada para uma amostra.
0

Meu C está um pouco enferrujado, então peço desculpas antecipadamente. Speedwise, eu posso entender os resultados. Mas estou confuso sobre como os dois arquivos saíram com o mesmo hash MD5. Talvez um loop for execute o mesmo, mas as 2 linhas de código a seguir não gerariam um assembly diferente?

myArray[i++] = "hello";

vs

myArray[++i] = "hello";

O primeiro grava o valor na matriz e depois incrementa i. Os segundos incrementos são gravados na matriz. Não sou especialista em montagem, mas não vejo como o mesmo executável seria gerado por essas duas linhas de código diferentes.

Apenas meus dois centavos.

Jason Z
fonte
1
@ Jason Z A otimização do compilador ocorre antes que a montagem seja finalizada, veria que a variável i não é usada em nenhum outro lugar na mesma linha; portanto, manter seu valor seria um desperdício, provavelmente o inverte para o i ++. Mas isso é apenas um palpite. Mal posso esperar até que um dos meus palestrantes tente dizer que é mais rápido e que eu seja o cara que corrige uma teoria com evidências práticas. Eu posso quase sentir a animosidade já ^ _ ^
Tarks
3
"Meu C está um pouco enferrujado, então peço desculpas antecipadamente." Não há nada errado com o seu C, mas você não leu a pergunta original na íntegra: "Existe uma diferença de desempenho entre i ++ e ++ i se o valor resultante não for usado? " Observe o itálico. No seu exemplo, o 'resultado' de i ++ / ++ i é usado, mas no loop idiomático for, o 'resultado' do operador de pré / pós-incremento não é usado para que o compilador possa fazer o que quiser.
Roddy
2
no seu exemplo, o código seria diferente, porque você está usando o valor. o exemplo em que eles eram iguais estava usando apenas o ++ para o incremento e não usando o valor retornado por nenhum dos dois.
John Gardner
1
Correção: "o compilador verificaria que o valor de retorno do i ++ não é usado, portanto o alteraria para o ++ i". O que você escreveu está errado também porque você não pode ter i junto com um dos i ++, i ++ na mesma linha (instrução), esse resultado é indefinido.
Blaisorblade 15/01/09
1
Mudar foo[i++]para foo[++i]sem alterar qualquer outra coisa obviamente mudaria a semântica do programa, mas em alguns processadores ao usar um compilador sem uma lógica de otimização de elevação de loop, incrementar pe qexecutar uma vez e depois executar um loop que executa, por exemplo, *(p++)=*(q++);seria mais rápido do que usar um loop que executa *(++pp)=*(++q);. Para loops muito apertados em alguns processadores, a diferença de velocidade pode ser significativa (mais de 10%), mas esse é provavelmente o único caso em C em que o pós-incremento é materialmente mais rápido que o pré-incremento.
supercat