Qual foi o pior abuso de macros / pré-processador do mundo real que você já se deparou (por favor, não há respostas inventadas da IOCCC * haha *)?
Adicione um pequeno trecho ou história, se for realmente divertido. O objetivo é ensinar algo em vez de sempre dizer às pessoas "nunca use macros".
ps: Eu já usei macros antes ... mas geralmente me livrei delas eventualmente quando tenho uma solução "real" (mesmo que a solução real esteja embutida para que se torne semelhante a uma macro).
Bônus: dê um exemplo em que a macro era realmente melhor do que uma solução que não é macro.
Pergunta relacionada: Quando as macros C ++ são benéficas?
c++
c
macros
preprocessor
Trevor Boyd Smith
fonte
fonte
Respostas:
De memória, parecia algo assim:
Sim, está certo, não há chaves de fechamento em nenhuma das funções. O destaque da sintaxe era uma bagunça, então ele usou o vi para editar (não o vim, ele tem uma sintaxe colorida!)
Ele era um programador russo que havia trabalhado principalmente em linguagem assembly. Ele era fanático por economizar o máximo de bytes possível porque já havia trabalhado em sistemas com memória muito limitada. "Era para satélite. Apenas muito poucos bytes, então usamos cada byte para muitas coisas". (mexendo um pouco, reutilizando bytes de instruções da máquina para seus valores numéricos) Quando tentei descobrir que tipos de satélites, só consegui obter "Satélite em órbita. Para fazer órbita".
Ele tinha duas outras peculiaridades: um espelho convexo montado sobre o monitor "Para saber quem está assistindo", e uma saída súbita ocasional da cadeira para fazer dez flexões rápidas. Ele explicou este último como "O compilador encontrou um erro no código. Isso é uma punição".
fonte
Meu pior:
Passei dois dias da minha vida rastreando algum problema de contagem de ref COM multi-threaded porque algum idiota colocou isso em um arquivo de cabeçalho. Não vou mencionar a empresa em que trabalhei na época.
A moral desta história? Se você não entender alguma coisa, leia a documentação e aprenda sobre ela. Não basta fazer isso desaparecer.
fonte
fonte
for (;;)
idioma, caso contrário, adicionaria imediatamente essa macro ao meu código.(defmacro ever ())
e então(require 'cl (ever))
Desafio: Alguém pode fazer isso com menos definições e estruturas? ;-)
fonte
public
estatic as nothing,
void` comoint
, emain(x)
comomain()
, entãopublic static void main(String[] args)
se transforma emint main()
. Então seSystem
transforma emS s;s
, então seSystem.out.println("Hello World!");
transforma emS s; s.out.println("Hello World!");
qual chama aprintln
função naF
estrutura naS
estrutura.fonte
class
palavra - chave e o primeiro modificador de acesso.#define class struct #define protected public
Foi brincadeira de alguém, não foi divertido pelos afetados
fonte
O hediondo:
Sério, se você quiser codificar em Pascal, compre um compilador Pascal, não destrua a bela linguagem C.
fonte
Um 'arquiteto', um cara muito humilde, você sabe o tipo, tinha o seguinte:
porque ele gostava de digitar rápido. O cirurgião cerebral costumava gritar com pessoas mais inteligentes que ele (que eram praticamente todo mundo) e ameaçava usar o cinto preto nelas.
fonte
killall rn
?Mundo real? O MSVC possui macros em minmax.h, chamadas
max
emin
, que causam um erro do compilador toda vez que pretendo usar astd::numeric_limits<T>::max()
função padrão .fonte
Uma mistura entre sintaxe Pascal e palavras-chave em francês:
fonte
Raymond Chen tem um discurso muito bom contra o uso de macros de controle de fluxo . Seu melhor exemplo é direto do código-fonte do shell Bourne original:
fonte
if
...else
...elif
...fi
ecase
...esac
antes (na própria linguagem que Bourne inventou para sh), masloop
...pool
é uma verdadeira jóia.Gostaria de enviar para o concurso uma gema chamada caos-pp , que implementa uma linguagem funcional por meio das macros do pré-processador.
Um dos exemplos é o cálculo do 500º número de fibonacci inteiramente pelo pré-processador:
O código original antes do pré-processador tem a seguinte aparência:
Ao pré-processar o arquivo, obtemos o seguinte resultado (após uma longa espera):
fonte
Diretamente do Qt:
Muito bom interagir com outras bibliotecas como boost :: signs ... Apenas um exemplo, existem muitas outras no Qt que criam códigos engraçados como:
E isso é C ++ ... mas de repente:
O C ++ não é mais válido.
fonte
O Windows.h possui muitas funções que abusam das macros.
MrValdez está irritado com a macro GetObject encontrada no Windows.h
A macro GetObject altera a função GetObject () para GetObjectA () ou GetObjectW () (dependendo se a compilação for compilada em não-unicode e unicode, respectivamente)
MrValdez odeia ter que fazer antes da linha de função GetObject
A alternativa é alterar o nome da função para algo como GetGameObject ()
jdkoftinoff nos comentários acertou em cheio: O problema é que todas as funções da API do Windows são macros.
Adam Rosenfield mencionou que os problemas podem ser corrigidos definindo NOGDI, WIN32_LEAN_AND_MEAN, NOMINMAX, etc. antes de incluir o windows.h para remover os problemas.
fonte
isso é tão ruim. É aleatório, o que significa que é acionado em locais diferentes o tempo todo, muda a declaração de retorno, que geralmente possui algum código que pode falhar por si só, altera a palavra-chave de aparência inocente que você nunca suspeitará e usa exceção do espaço padrão, para que você não tente pesquisar nas fontes para encontrar a fonte. Apenas brilhante.
fonte
Um colega de trabalho e eu encontramos essas duas gemas em alguns dos nossos códigos para streaming de objetos. Essas macros foram instanciadas em cada arquivo de classe que fazia streaming. Não apenas esse código hediondo foi espalhado por toda a nossa base de códigos, quando abordamos o autor original sobre ele, ele escreveu um artigo de 7 páginas em nosso wiki interno, defendendo isso como a única maneira possível de realizar o que ele estava tentando fazer aqui.
Escusado será dizer que, desde então, foi refatorado e não é mais usado em nossa base de código.
Não se deixe impressionar pelas palavras-chave destacadas. Esta é toda uma macro
Atualização (17 de dezembro de 2009):
Mais boas notícias sobre esse hediondo autor de macro. Em agosto, o funcionário responsável por essa monstruosidade foi demitido.
fonte
Eu mesmo fiz o seguinte e acho que aprendi algo com isso.
Em 1992, escrevi um pequeno intérprete de Lisp. Não foi implementado no C normal, mas em uma linguagem do tipo C interpretada. Essa linguagem do tipo C usava o pré-processador C padrão.
Obviamente, o intérprete Lisp continha as funções car , que são usadas no Lisp para retornar o primeiro elemento de uma lista e cdr , que retorna o restante da lista. Eles foram implementados assim:
(Os dados foram armazenados em matrizes, pois não havia estruturas. CONS_OFFSET é a constante 1000.)
car e cdr são usados com freqüência no Lisp e são curtos, e como as chamadas de função não eram muito rápidas na linguagem de implementação, otimizei meu código implementando essas duas funções do Lisp como macros:
CHECK_CONS verifica se seu argumento é realmente uma lista e, como esse também é usado com frequência no intérprete e é curto, escrevi esse também como uma macro:
IS_CONS e LISP_ERROR também foram usados com freqüência, então eu os transformei em macros também:
Parece razoável?
Mas então, por que todo o sistema travou nesta linha:
Eu trabalhei muito tempo para encontrar o problema, até finalmente verificar o que aquela linha curta foi expandida pelo pré-processador. Foi expandido para uma linha de 31370 caracteres, que eu dividi aqui em linhas (502 delas) para maior clareza:
fonte
I optimized my code by implementing those [..] functions as macros
- famosas últimas palavras ...Uma vez tive que portar um aplicativo C do unix para o windows, cuja natureza específica permanecerá sem nome para proteger os culpados. O sujeito que o escreveu era um professor não acostumado a escrever código de produção e claramente chegara ao C de outro idioma. Acontece também que o inglês não era sua primeira língua, embora o país de origem da maioria das pessoas fale muito bem.
Sua aplicação fez uso pesado do pré-processador para transformar a linguagem C em um formato que ele pudesse entender melhor. Mas as macros que ele mais usou foram definidas em um arquivo de cabeçalho chamado 'Thing.h' (sério), que incluía o seguinte:
... que ele costumava escrever monstruosidades como as seguintes:
Todo o projeto (~ 60.000 LOC) foi escrito em um estilo semelhante - marco inferno, nomes estranhos, jargão olde-inglês etc. Felizmente, conseguimos reproduzir o código desde que encontrei uma biblioteca OSS que executava o mesmo algoritmo dezenas vezes mais rápido.
(Copiei e editei esta resposta que fiz originalmente sobre esta questão ).
fonte
O pior que eu já encontrei foi em um produto que continha um conjunto de executáveis em que o líder técnico designado não havia descoberto as bibliotecas.
Em vez disso, ele tinha conjuntos de arquivos que eram compartilhados em várias pastas do Visual Source Safe. Ele então percebeu que eles precisavam se comportar de maneira um pouco diferente para cada aplicação.
Há várias etapas de refatoração que você pode aplicar aqui.
Em vez disso, ele usou #ifdefs
fonte
O uso do pré-processador LINE para gerar um ID exclusivo para mensagens transmitidas pela rede:
Este é um exemplo em que a macro realmente era melhor do que uma solução não macro:
Em classes de solução não macro, funções e variáveis precisam ser criadas para acompanhar o ID da mensagem. O desenvolvedor pode ou não dificultar o rastreamento do ID da mensagem, o que é mais fácil de ler e depurar.
Além disso, é mais fácil adicionar novas mensagens apenas adicionando a mensagem à fonte.
A desvantagem dessa situação é que o arquivo deve ser incluído em todo o código que usa mensagens. O tempo de compilação aumentaria sempre que uma mensagem fosse editada.
fonte
Um exemplo bastante ruim:
Isso permite que uma estrutura C que contenha uma variável de membro chamada
class
seja manipulada por um compilador C ++. Existem dois cabeçalhos com essa construção; um deles também contém '#undef class' no final e o outro não.fonte
@class
vez declass
.Em um ano do Concurso Internacional de Codificação C Ofuscada, houve uma entrada em que todo o programa era:
P
Com a condição de que você possa definir
P
no makefile como o programa que desejar.Pelo que me lembro, ele venceu em uma das categorias e, no ano seguinte, surgiu uma regra que não permitia esse estilo de entrada.
(Edit: seis meses depois ou algo assim ... Tenho certeza que a coisa "No IOCCC" não estava na pergunta principal quando escrevi isso ...)
fonte
Eu estava entediado um dia e estava brincando com blocos no Objective-C ...
permitindo coisas "interessantes" como:
(algumas definições de função e classe não são mostradas por uma questão de brevidade)
fonte
O pior que vi foi o não uso :-)
Alguém escreveu uma função strcpy (acho que foi isso ... há mais de 10 anos atrás) dentro de um método (porque não queria a sobrecarga de chamar strcpy ... suspiro).
Eles disseram que isso não funcionaria para caracteres japoneses, então eles adicionaram um "se" no início para executar ASCII ou Unicode. Naquele momento, o código tinha cerca de uma tela ... provavelmente matando a coerência do cache e apagando suas supostas economias para a inclusão do código.
O código era idêntico, exceto para os tipos (portanto, deveria ter usado uma macro).
É claro que o strcpy que eles escreveram foi muito mais lento que o assembler ajustado manualmente que estava na biblioteca padrão ...
É claro que se eles tivessem feito tudo isso como uma macro, poderiam ter sido substituídos por uma chamada para strcpy ...
Claro que abandonei a empresa (não diretamente por causa disso ...)
fonte
The code was identical save for the types (so should have used a macro).
Não, ele deveria ter usado um modelo.O obrigatório
e
Quem sabia?
fonte
A pessoa que fez isso se explicou alguns anos depois - a maioria (se não todas) das funções da biblioteca C retornam 0 como uma indicação de que tudo correu bem. Então, ele queria escrever código como:
Escusado será dizer que ninguém em nossa equipe (testador ou desenvolvedor) ousou olhar seu código novamente.
fonte
#define FLAG_SUCCESS 0
?Eu mantenho o código que tem gotos nas macros. Portanto, uma função terá um rótulo no final, mas nenhum goto visível no código da função. Para piorar a situação, a macro está no final de outras instruções geralmente fora da tela, a menos que você role horizontalmente.
fonte
goto
instruções e as definições dos rótulos de destino. Totalmente mágico.fonte
Por um colega de classe que não entendeu as regras sobre números mágicos:
#define TWO_HUNDRED_AND_EIGHTY_THREE_POINT_ONE 283.1
fonte
ASA - http://www.ingber.com/#ASA
Você realmente precisa baixá-lo para apreciá-lo. Todo o fluxo de trabalho é determinado por macros. É completamente ilegível. Como um exemplo -
etc etc.
E isso é apenas configurar as opções. todo o programa é assim.
fonte