O que deixa os desenvolvedores de C tão curiosos se “i ++ == ++ i”? [fechadas]

15

Apenas uma observação aleatória, parece que no StackOverflow.com, há perguntas sobre se "++ i == i ++". Essa pergunta é feita o tempo todo, acho que a vi perguntada cerca de 6 ou 7 vezes nos últimos 2 meses.

Eu só me pergunto por que os desenvolvedores C estão tão interessados ​​nisso? O mesmo conceito / pergunta existe também para desenvolvedores de C # e Java, mas acho que vi apenas uma pergunta relacionada ao C #.

É porque tantos exemplos usam ++ i? É porque existe algum livro ou tutorial popular? É porque os desenvolvedores de C adoram amontoar o máximo possível em uma única linha para 'eficiência' / 'desempenho' e, portanto, encontram construções 'estranhas' usando o operador ++ com mais frequência?

Michael Stum
fonte
23
(Para mim, como C # dev, i ++ e ++ são iguais. Sei que não, mas se eu escrever código que depende da diferença, prefiro refatorá-lo para ser mais legível e esperar que o compilador e o JITter tomem cuidado. do mesmo, mas como um C # dev eu não estou tentando salvar um ou dois relógio ciclos porque eu sou relativamente ineficiente de qualquer maneira já)
Michael Stum
1
como programadores iniciantes, adoramos brincar com aritmética, lógica e curiosidade em saber como as coisas funcionam. Eu acho que essa é uma grande razão pela qual nós amamos essas perguntas. pode não ser um recurso inovador, mas com certeza é interessante! Não é esse o motivo de termos nos tornado programadores ?!
Chani
2
Você está literalmente se referindo à expressão ++i == i++ou, de maneira mais geral, à diferença de significado entre ++ie i++?
30513 Keith Thompson

Respostas:

30

Suspeito que pelo menos parte disso seja um pouco mais simples: mesmo agora, vemos muitas perguntas como essa começando no início do ano letivo e elas gradualmente diminuem ao longo do ano.

Como tal, acho que é justo adivinhar que algumas delas são simplesmente o resultado de aulas nas quais o professor fala pelo menos um pouco sobre isso, mas não explica muito bem seus pontos (muitas vezes não porque ele realmente não os entende). Especialmente com base nas pessoas que parecem fazer essas perguntas, poucas são baseadas na codificação real.

Jerry Coffin
fonte
14
Não é esse o oposto de setembro eterno? Setembro eterno foi quando a AOL começou a oferecer acesso à Usenet aos seus clientes, fazendo parecer que setembro (o mês em que novos alunos que começavam as aulas tradicionalmente bombardeavam os conselhos de administração) o ano todo.
Nlawalker 27/05
É uma teoria interessante, mas talvez nem sempre seja culpa dos professores se alguém não entendeu o material: talvez os alunos (1) não prestassem atenção suficiente durante a aula e (2) com preguiça de procurar uma resposta sobre o fluxo de pilha antes fazendo a mesma pergunta novamente.
Giorgio
12

Porque os programadores C precisam entender a ordem das operações. Os desenvolvedores de C # não usam necessariamente os operadores bit a bit (&, |, ~) ou prefixos, pois normalmente estamos mais preocupados com outras coisas. No entanto, o que nós C # devs não percebemos é que devemos saber o que os operadores que usamos diariamente fazem e como usá-los adequadamente. A maioria de nós evita os lugares onde isso pode ser um problema.

De cabeça para baixo, qual é o resultado desse snippet?

    double x = 5.5;
    Console.WriteLine(x++);
    x = 5.5;
    Console.WriteLine(++x);

Eu diria que um bom número de desenvolvedores C # experientes não tem idéia de qual é a saída para o console.

Nate Noonen
fonte
3
+1. Conhecer a diferença entre os operadores de incremento / decremento pré e pós-correção vale a pena em situações como essa.
Maulrus 02/11/10
4
Eu meio que entendi o ponto e também não conhecia a saída (acredito que seja 5,5 e 6,5, mas não tenho certeza), e para mim isso não importaria, pois eu a refatoraria para x ++; Console.WriteLine (x); imediatamente. No entanto, não sou totalmente ignorante, apenas acho que é um grande cheiro de código com usabilidade zero.
Michael Stum
8
A resposta para a pergunta não tem nada a ver com a ordem das operações ou a diferença entre os incrementos de prefixo e postfix. É uma questão de comportamento definido e indefinido.
David Thornley
2
Eu encontrei isso hoje. Algo como if (myList[i++] == item). Esperto. Eu achei que estava procurando a fonte de uma exceção IndexOutOfRange ... De fato, muito "inteligente".
Rmac
6
Acho que são 5,5 e 6,5, mas nunca o vi ++usado em um carro alegórico antes, e devo dizer que não parece muito apropriado. As pessoas fazem isso? (Eu prefiro += 1)
Bart van Heukelom
8

Eu acho que isso é óbvio. Em C #, para um int i, i++ == ++ié sempre falso, enquanto ++i == i++é sempre verdade, de forma confiável, e todos os interessados ​​podem descobrir isso facilmente, apenas aprendendo as regras do C # (ou simplesmente executando-o).

Em C e C ++, por outro lado, é quase indefinido porque depende do compilador, do ambiente de execução, da plataforma etc., por isso é uma pergunta muito mais difícil de responder, e muitas pessoas fazem isso.

Timwi
fonte
+1 - mas não é realmente uma pergunta mais difícil de responder. "indefinido" é uma palavra. Todas as coisas "depende de ..." são coisas com as quais a maioria das pessoas não se preocupa. Mesmo se você estiver escrevendo apenas para uma plataforma específica, deve usar os idiomas normais para o idioma como um todo, e a maioria dos usos dos operadores de pré-incremento e pós-incremento faz parte de alguns idiomas comuns.
31311 Steve314
+1: na verdade, responde à pergunta feita (ou seja, você não está lendo nas entrelinhas).
21813 Thomas Eding
7

É uma pergunta popular, porque é uma pergunta complicada. Está indefinido .

O link acima vai para uma FAQ na página inicial de Bjarnes Stroustrup, que aborda essa questão especificamente e explica por que essa construção é indefinida. O que diz é:

Basicamente, em C e C ++, se você ler uma variável duas vezes em uma expressão em que também a escreve, o resultado será indefinido.

Afirmar que a ordem de avaliação é indefinida gera um código com melhor desempenho.

user16764
fonte
5

Provavelmente porque em C, realmente importa se você escreve i++ou ++iquando faz aritmética de ponteiros. Lá, aumentar iantes ou depois de uma operação pode ser crucial. Eu daria um exemplo, mas a última vez que escrevi C foi há 10 anos ...

Em C #, nunca me deparei com uma situação que exigisse que eu pensasse i++ou ++iporque o AFAIK, pelos loops for / while, não importa.

Mladen Prajdic
fonte
3
ainda é importante compreender as diferenças em C # - só porque você parece apenas para usá-los em para / cada laços não significa que é o único lugar que você vai encontrá-los
STW
totalmente verdade isso.
Mladen Prajdic
3
Isso não é relevante para a pergunta. A questão não é sobre a diferença entre i++e ++i, mas combiná-los na mesma expressão.
David Thornley
@ David A questão é por que os programadores C estão curiosos sobre isso. A resposta (importa em C, não tanto em C #) é completamente relevante ".
Florian F
2

Alguns anos atrás, li que esses operadores eram considerados perigosos e tentei cavar mais informações. Se o stackoverflow estivesse ativo naquele momento, eu teria perguntado lá.

Agora é porque algumas pessoas distorcidas escrevem loops como

while( [something] )
{
  a[++j] = ++j;
}

Mesmo agora, não tenho muita certeza do que acontecerá / deveria acontecer, mas está bem claro para mim que vários ++ [var] na mesma linha estão pedindo problemas.

Eric
fonte
2
Incrementos tem um comportamento indefinido como parte de uma tarefa em C
tzenes
7
Atribuições como x = ++j;estão bem definidas em C. O item acima é indefinido porque jé modificado duas vezes sem pontos de sequência intervenientes.
Matthew Flaschen
2

Duas razões.

A implementação correta do ++ i é incrementar i e depois devolvê-lo. A implementação correta do i ++ é salvar o valor atual, incrementar i e retornar o valor salvo. Saber que isso não é implementado como sinônimo é importante.

A questão então se torna quando o compilador as aplica enquanto avalia uma expressão, como igualdade.

Se o teste de igualdade for feito primeiro, os operadores de pré e pós-incremento terão que escrever uma lógica diferente do que se o lado esquerdo (lhs) e o lado direito (rhs) forem avaliados primeiro e, em seguida, a igualdade.

É tudo uma ordem de operações, e isso, por sua vez, afeta o código que se escreve. E, não surpreendentemente, nem todos os idiomas estão de acordo.

A lista de testes básicos permite que os desenvolvedores testem para ver se suas suposições estão corretas, bem como se a implementação real corresponde à especificação de idioma.

Isso pode ter todos os tipos de impacto ao trabalhar com ponteiros, loops ou retornar valores.

Walt Stoneburner
fonte
5
Testes básicos sobre isso serão enganosos, porque é um comportamento indefinido. Se funcionar exatamente como você espera desta vez, não há garantia de que será da próxima vez.
18730 David Thornley
Você respondeu à pergunta errada. Você deve responder por que os programadores C estão curiosos sobre isso.
21711 Hugo
Seu segundo parágrafo está incorreto de qualquer maneira (antes de C ++ 11, pelo menos): o comportamento de ++ié usar o valori+1 e em algum momento, talvez antes ou depois disso, mas antes do próximo ponto de sequência, incrementei .
2121 MM
@MattMcNabb - Você pode me indicar uma especificação para isso? Gostaria de saber se as coisas mudaram na implementação. Nos dias em que C mapeou bem o assembly do PDP, o ++ i injetou uma instrução INC, enquanto a versão do sufixo precisava copiar o valor em um registro para usar uma instrução após o incremento. O que constituiu a necessidade da mudança que você descreveu?
Walt Stoneburner
2

Eu acho que é uma coisa de choque cultural.

Como já apontado, o comportamento de uma expressão em C ou C ++ pode ser indefinido porque a ordem de execução dos pós-incrementos etc. não é estritamente definida. O comportamento indefinido é bastante comum em C e, é claro, muito disso foi importado para C ++.

Para alguém que fez alguma programação em outra linguagem - alguém que entendeu a idéia de que as linguagens de programação deveriam ser precisas e que os computadores deveriam fazer o que eles deveriam fazer ... bem, é um choque descubra que C é intencionalmente vago sobre algumas coisas.

Steve314
fonte
C é assim porque foi projetado para suportar muito mais plataformas do que as que existiam quando o C # foi definido, incluindo as mais estranhas plataformas incorporadas ou de mainframe que você pode imaginar. C #, por outro lado, roda em ... x86 e 360? talvez ARM também? Nada mais. É por isso que o C # pode definir muito mais.
DeadMG
++ Além disso, o C não foi construído pela primeira vez em um PDP-11? Onde havia instruções de incremento automático? C queria estar "perto da máquina" para poder fazer uso útil do conjunto de instruções.
Mike Dunlavey
@MikeDunlavey: Não, os C ++e os --operadores não eram baseados no PDP-11, que não existia quando esses operadores foram introduzidos na linguagem B anterior do C. Consulte cm.bell-labs.com/who/dmr/chist.html e procure por "incremento automático".
30513 Keith Thompson
1

Talvez seja apenas o fato de os desenvolvedores de C usarem o incremento ++ com mais frequência em geral - visto que C não possui "foreach" ou declaração semelhante para iterar através de matrizes. Ah, e é claro, aritmético, como mencionado anteriormente!

Robert Roos
fonte
1
Bom ponto, esqueci que foreach é um conceito relativamente moderno.
Michael Stum
-1

A diferença entre as duas partes: a postagem e o pré-incremento estão funcionando da maneira que esses dois pedaços de código devem funcionar em todos os idiomas. ISTO NÃO É DEPENDENTE DA LÍNGUA !!!

++i

Isso é pré-incremento. Este trecho de código aumentará primeiro o valor de iantes de enviar o valor para a linha em que é usado.

i++

Este é o pós-incremento. Este trecho de código retornará o valor de iantes de aumentar o valor da ilinha em que é usado.

Em outro pequeno exemplo:

int main(void)
{
  int i = 0; 
  int result; 
  result = 10 + ++i; 
  printf("%d \n", result); // = 11 

  int j = 0; 
  result = 10 + j++; 
  printf("%d \n", result);// = 10
  return 0;
}

Este código compilando com resultados no codepad.

Isso tem a ver com a implementação interna da sobrecarga do operador.

++i aumenta diretamente o valor (e, portanto, é um pouco mais rápido)

i++primeiro cria uma cópia que é retornada ao local onde necessário e depois o valor original da ivariável é aumentado em um.

Espero que isso esteja claro agora.

Krie999
fonte
No entanto, isso não aborda a questão real: por que os desenvolvedores de C perguntam sobre isso mais do que outros. O OP entende os operadores.
Martijn Pieters
Além disso, esta resposta está incorreta. ++inão é mais rápido e i++não cria uma cópia. Além disso, ++icomporta-se de maneira ligeiramente diferente em C e em C ++, sem falar entre outras linguagens.
MM