Edição global: desculpe pessoal, eu fiquei demitida e escrevi muitas bobagens. Apenas um velhote velho reclamando.
Eu queria acreditar que o C havia sido poupado, mas, desde o C11, ele foi comparado com o C ++. Aparentemente, saber o que o compilador fará com efeitos colaterais em expressões requer agora resolver um pequeno enigma matemático envolvendo uma ordenação parcial de seqüências de código com base em um "está localizado antes do ponto de sincronização de".
Por acaso, eu projetei e implementei alguns sistemas embarcados críticos em tempo real nos dias de K&R (incluindo o controlador de um carro elétrico que poderia fazer com que as pessoas colidissem com a parede mais próxima se o motor não fosse controlado, um industrial de 10 toneladas um robô que poderia esmagar as pessoas em uma pasta, se não fosse comandado adequadamente, e uma camada de sistema que, apesar de inofensiva, teria algumas dezenas de processadores sugando seu barramento de dados com menos de 1% de sobrecarga do sistema).
Talvez eu seja muito senil ou estúpido para obter a diferença entre indefinido e não especificado, mas acho que ainda tenho uma boa idéia do que significa execução simultânea e acesso a dados. Na minha opinião indiscutivelmente informada, essa obsessão do C ++ e agora do C com seus idiomas de estimação assumindo problemas de sincronização é um sonho caro. Você sabe o que é execução simultânea e não precisa de nenhum desses dispositivos, ou não, e faria um favor ao mundo em geral, sem tentar mexer com ele.
Todo esse caminhão de abstrações de barreira de memória de dar água nos olhos é simplesmente devido a um conjunto temporário de limitações dos sistemas de cache com várias CPUs, que podem ser encapsulados com segurança em objetos comuns de sincronização do SO, como, por exemplo, os mutexes e variáveis de condição C ++ ofertas.
O custo desse encapsulamento é apenas uma queda minúscula no desempenho, em comparação com o que um uso de instruções específicas da CPU de baixa granularidade poderia alcançar em alguns casos.
A volatile
palavra-chave (ou um#pragma dont-mess-with-that-variable
por tudo que eu, como programador de sistemas, cuidado) teria sido suficiente para dizer ao compilador para parar de reordenar os acessos à memória. O código ideal pode ser facilmente produzido com diretivas diretas asm para espalhar códigos de driver e SO de baixo nível com instruções específicas da CPU ad hoc. Sem um conhecimento profundo de como o hardware subjacente (sistema de cache ou interface de barramento) funciona, você provavelmente escreverá um código inútil, ineficiente ou com defeito.
Um ajuste minucioso da volatile
palavra - chave e de Bob teria sido todo mundo, menos o tio dos programadores de nível mais baixo. Em vez disso, a turma habitual de loucos por matemática em C ++ teve um dia de campo projetando mais uma abstração incompreensível, cedendo à tendência típica de projetar soluções procurando problemas inexistentes e confundindo a definição de uma linguagem de programação com as especificações de um compilador.
Somente desta vez a mudança necessária para desfigurar um aspecto fundamental de C também, uma vez que essas "barreiras" precisavam ser geradas mesmo em código C de baixo nível para funcionar corretamente. Que, entre outras coisas, causou estragos na definição de expressões, sem nenhuma explicação ou justificativa.
Como conclusão, o fato de um compilador produzir um código de máquina consistente a partir dessa parte absurda de C é apenas uma conseqüência distante da maneira como os funcionários do C ++ lidaram com possíveis inconsistências nos sistemas de cache do final dos anos 2000.
Isso causou uma confusão terrível em um aspecto fundamental de C (definição de expressão), de modo que a grande maioria dos programadores de C - que não se importam com os sistemas de cache, e com razão - agora são obrigados a confiar nos gurus para explicar a diferença entre a = b() + c()
e a = b + c
.
Tentar adivinhar o que será dessa matriz infeliz é uma perda líquida de tempo e esforços de qualquer maneira. Independentemente do que o compilador faça disso, esse código está patologicamente errado. A única coisa responsável a fazer com isso é enviá-lo para a lixeira.
Conceitualmente, os efeitos colaterais sempre podem ser removidos das expressões, com o esforço trivial de permitir explicitamente que a modificação ocorra antes ou depois da avaliação, em uma declaração separada.
Esse tipo de código de merda pode ter sido justificado nos anos 80, quando você não esperava que um compilador otimizasse nada. Mas agora que os compiladores há muito se tornaram mais inteligentes do que a maioria dos programadores, tudo o que resta é um pedaço de código de merda.
Também não entendo a importância desse debate indefinido / não especificado. Você pode confiar no compilador para gerar código com um comportamento consistente ou não pode. Se você chama isso de indefinido ou não especificado, parece um ponto discutível.
Na minha opinião indiscutivelmente informada, C já é perigoso o suficiente em seu estado de K&R. Uma evolução útil seria adicionar medidas de segurança de senso comum. Por exemplo, ao usar essa ferramenta avançada de análise de código, as especificações forçam o compilador a implementar para, pelo menos, gerar avisos sobre o código bonkers, em vez de gerar silenciosamente um código potencialmente não confiável ao extremo.
Mas, em vez disso, os caras decidiram, por exemplo, definir uma ordem de avaliação fixa no C ++ 17. Agora, todo imbecil de software é incitado ativamente a colocar efeitos colaterais em seu código de propósito, aproveitando a certeza de que os novos compiladores lidarão ansiosamente com a ofuscação de uma maneira determinística.
K&R foi uma das verdadeiras maravilhas do mundo da computação. Por vinte dólares, você obtém uma especificação abrangente da linguagem (vi indivíduos solteiros escreverem compiladores completos usando apenas este livro), um excelente manual de referência (o índice geralmente indica algumas páginas da resposta à sua pergunta). questão) e um livro didático que ensina a usar o idioma de maneira sensata. Complete com argumentos, exemplos e sábias palavras de aviso sobre as inúmeras maneiras pelas quais você pode abusar do idioma para fazer coisas muito, muito estúpidas.
Destruir essa herança por tão pouco ganho parece um desperdício cruel para mim. Mas, novamente, eu poderia muito bem deixar de entender completamente o ponto. Talvez uma alma amável possa me apontar na direção de um exemplo de novo código C que aproveite significativamente esses efeitos colaterais.