Que dicas gerais você tem para jogar golfe em C? Estou procurando idéias que possam ser aplicadas para codificar problemas de golfe em geral que sejam pelo menos um pouco específicos para C (por exemplo, "remover comentários" não é uma resposta). Poste uma dica por resposta. Além disso, inclua se sua dica se aplica a C89 e / ou C99 e se ela funciona apenas em determinados compiladores.
137
Respostas:
Use o XOR bit a bit para verificar a desigualdade entre números inteiros:
if(a^b)
em vez deif(a!=b)
salvar 1 caractere.fonte
a-b
dá o mesmo efeito.a*b
vez dea&&b
(tem precedência diferente, pode ou não ser ruim). Se você sabe a / = -b (por exemplo, eles são sem sinal), entãoa||b
==a+b
?:
(em vez de se): por exemplo, fazer apenas algo se for diferente:a^b?_diff_:;
?:
operador que é apenas equivalente aa ? a : b
main
Lista de argumentos do abuso para declarar uma ou mais variáveis inteiras:(responda a O alfabeto nas linguagens de programação )
Essa solução também abusa do fato de que
a
(akaargc
) inicia como1
, desde que o programa seja chamado sem argumentos.Use variáveis globais para inicializar as coisas para zero:
(resposta a Anagram Code Golf! )
fonte
O operador vírgula pode ser usado para executar várias expressões em um único bloco, evitando chaves:
Saídas:
1 2
fonte
break
.break
é uma afirmação, e esta resposta está falando sobre expressões.Evite declarações catastróficas do tipo argumento de função
Se você está declarando uma função em que todos os cinco argumentos são
int
s, a vida é boa. você pode simplesmente escreverMas suponha
d
que seja umchar
, ou mesmo umint*
. Então você está ferrado! Se um parâmetro for precedido por um tipo, todos eles deverão ser:Mas espere! Existe uma maneira de contornar essa explosão desastrosa de personagens inúteis. É assim:
Isso economiza em uma
main
declaração padrão se você precisar usar os argumentos da linha de comando:é dois bytes menor que
Fiquei surpreso ao descobrir isso, pois ainda não o encontrei no PPCG.
fonte
-std=gnu99
e agora não é portátil. No clc-speak, você nem está escrevendo o código "C" em si, mas o "Gnu99-C". Por aqui, quase sempre ignoramos isso, mas é bom mencioná-lo se você postar um código específico do compilador. Às vezes, as pessoas realmente fazem o download e executam esses programas. :)-std=c89
dizer ao gcc ou clang para compilar seu código de acordo com o padrão mais antigo, que permite int implícito apenas com um aviso.Em vez de> = e <=, você pode simplesmente usar a divisão inteira (/) quando os valores comparados estiverem acima de zero, o que salva um caractere. Por exemplo:
O que, é claro, ainda é reduzido, usando, por exemplo, just> e ^ (uma maneira inteligente de evitar escrever && ou || em alguns casos).
O truque da divisão inteira é, por exemplo, útil para decidir se um número é menor que 100, pois isso salva um caractere:
Isso também é bom nos casos em que é necessária maior precedência.
fonte
putchar(c>31&c<127?c:46);
Certos compiladores, como o GCC, permitem omitir
#include
tipos básicos s, param e return paramain
.A seguir, é apresentado um programa C89 e C99 válido que compila (com avisos) o GCC:
Observe que o
#include
for stdio.h está ausente, o tipo de retorno paramain
está ausente e a declaração de tipoi
está ausente.fonte
printf()
(ou qualquer função variável) sem um protótipo causa comportamento indefinido . O GCC não compila o padrão C por padrão. Se você invocar o gcc no modo C89 (gcc -ansi -pedantic
) ou C99 (gcc -std=c99 -pedantic
), receberá algumas reclamações, pelo menos no último caso.O operador condicional ternário
?:
muitas vezes pode ser usado como um carrinho na de simplesif
-else
declarações em uma economia considerável.Diferente do equivalente em c ++, o operador não produz formalmente um valor l , mas alguns compiladores (principalmente o gcc) permitem que você se dê bem com ele, o que é um ótimo bônus.
fonte
&&
e||
também pode ser usado:if(x==3)f()
fica com a sua sugestãox==3?f():0
e pode ser melhorado ainda mais parax==3&&f()
. Mas tenha cuidado com a precedência do operador - sef()
for substituído pory=1
, a&&
solução requer um conjunto extra de parênteses.?:
produz um valor l. Posso usar isso no código de produção? lolx==3&&f()
pode ser ainda maisx^3||f()
http://graphics.stanford.edu/~seander/bithacks.html
Bits são bons.
Mas com precedências diferentes, e não mude x como ++ e -. Além disso, você pode usar isso em casos realmente específicos: ~ 9 é menor que -10.
Isso é mais esotérico, mas tive ocasião de usá-lo. Se você não se importa com curtos-circuitos
Além disso:
fonte
(x/y) == (x>=y)
) é realmente útil.Use lambdas (não portável)
Ao invés de
ou (somente GCC)
ou (llvm com suporte a blocos)
tente algo como
... onde a cadeia de caracteres citada contém as instruções de linguagem de máquina da função "lambda" (em conformidade com todos os requisitos da ABI da plataforma).
Isso funciona em ambientes nos quais as constantes de sequência são marcadas como executáveis. Por padrão, isso é verdade no Linux e OSX, mas não no Windows.
Uma maneira boba de aprender a escrever suas próprias funções "lambda" é escrever a função em C, compilá-la, inspecioná-la com algo parecido
objdump -D
e copiar o código hexadecimal correspondente em uma string. Por exemplo,... quando compilado
gcc -Os -c
para um destino Linux x86_64 gera algo comoGNU CC
goto
:Você pode chamar essas "funções lambda" diretamente, mas se o código que você está chamando não aceita parâmetros e não retorna, você pode usar
goto
para salvar alguns bytes. Então, ao invés deou (se o seu ambiente não tiver glifos em árabe)
Experimentar
ou
Neste exemplo,
eb fe
é a linguagem de máquina x86 para algo comofor(;;);
e é um exemplo simples de algo que não aceita parâmetros e não retorna :-)Acontece que você pode
goto
codificar que retorna para um pai que está chamando.O exemplo acima (pode ser compilado e executado no Linux com
gcc -O
) é sensível ao layout da pilha.EDIT: Dependendo da sua cadeia de ferramentas, talvez você precise usar o
-zexecstack
sinalizador de compilação.Se não for imediatamente aparente, essa resposta foi escrita principalmente para os risos. Não me responsabilizo por um golfe melhor ou pior ou por resultados psicológicos adversos ao ler isso.
fonte
Use cursores em vez de ponteiros. Pegue o
brk()
no início e use-o como um ponteiro de base .Em seguida, faça um #define para acesso à memória.
M
torna-se um postfix*
aplicado a números inteiros. (O antigo truque de [x] == x [a].)Mas tem mais! Em seguida, você pode ter argumentos e retornos de ponteiro em funções menores que as macros (especialmente se você abreviar 'return'):
Para criar um cursor a partir de um ponteiro, você subtrai o ponteiro base, produzindo um ptrdiff_t, que trunca em um int, as perdas são suas.
Essa técnica é usada na minha resposta para Escrever um intérprete para o cálculo lambda sem tipo .
fonte
Defina parâmetros em vez de variáveis.
f(x){int y=x+1;...}
f(x,y){y=x+1;...}
Você não precisa realmente passar o segundo parâmetro.
Além disso, você pode usar a precedência do operador para salvar parênteses.
Por exemplo,
(x+y)*2
pode se tornarx+y<<1
.fonte
x+y*2
, salvando mais um caractere.x+y*2
não é o mesmo, devido à precedência do operador.x+y<<1
exemplo, supondo que ele estivesse sendo avaliado comox+(y<<1)
e sugeri o*2
contrário. Eu não sabia operações bitshift foram avaliadas como por exemplo(x+y)<<2
Como geralmente
EOF == -1
, use o operador NOT bit a bit para verificar o EOF:while(~(c=getchar()))
ouwhile(c=getchar()+1)
e modifique o valor de c em todos os lugaresfonte
while(1+c=getchar())
funcionaria?+
tem precedência mais alta que o operador de atribuição=
, portanto1+c=getchar()
é equivalente a(1+c)=getchar()
, que não é compilado porque(1+c)
não é um valor l.O operador ternário
?:
é incomum, pois possui duas partes separadas. Por esse motivo, fornece uma brecha para as regras de precedência padrão do operador. Isso pode ser útil para evitar parênteses.Veja o seguinte exemplo:
A abordagem usual do golfe é substituir
if
por&&
, mas devido à baixa precedência do operador de vírgula, você precisa de um par extra de parênteses:A seção do meio do operador ternário não precisa de parênteses, no entanto:
Comentários semelhantes se aplicam aos subscritos da matriz.
fonte
b-=a=b
é ainda mais curto. O?:
truque ainda é útil,-=
porque também tem pouca preferência.x>0||(y=3)
,x>0?0:(y=3)
é inútil, masx<1?y=3:0
faz o trabalho.x>5?:y=1
Qualquer parte do seu código que se repita várias vezes é candidata à substituição pelo pré-processador.
é um caso de uso muito comum se o código envolver mais do que algumas funções. Outras palavras-chave longish como
while
,double
,switch
, ecase
também são candidatos; bem como tudo o que é idomatic no seu código.Geralmente, reservo caracteres maiúsculos para esse fim.
fonte
-DR=return
. Observe que, se você incluir determinados caracteres, pode ser necessário ter aspas simples ou duplas ao redor da definição-DP='puts("hello")'
.Se o seu programa estiver lendo ou gravando em cada etapa, tente sempre usar a função de leitura e gravação em vez de getchar () e putchar () .
Exemplo ( inverter stdin e colocar em stdout )
Exercício: Use esta técnica para obter uma boa pontuação aqui .
fonte
Loops Reversos
Se puder, tente substituir
com
fonte
Se você precisar gerar um único caractere de nova linha (
\n
), não useputchar(10)
, useputs("")
.fonte
Faça uso de valores de retorno para zero coisas. Se você chamar alguma função, e essa função retornar zero em condições normais, poderá colocá-la em um local em que se espera zero. Da mesma forma, se você souber que a função retornará diferente de zero, com a adição de um estrondo. Afinal, você não realiza o tratamento adequado de erros em um código de golfe, certo?
Exemplos:
fonte
Atribuir em vez de retornar.
Este não é realmente o padrão C, mas funciona com todos os compiladores e CPUs que eu conheço:
tem o mesmo efeito que:
Como o primeiro argumento é armazenado no mesmo registro da CPU que o valor de retorno.
Nota: Conforme observado em um comentário, esse é um comportamento indefinido e não é garantido que funcione para todas as operações. E qualquer otimização do compilador simplesmente ignorará.
X-macros
Outro recurso útil: X-Macros pode ajudá-lo quando você tiver uma lista de variáveis e precisar executar alguma operação que envolva todas elas:
https://en.wikipedia.org/wiki/X_Macro
fonte
-O0
sempre escolhe avaliar expressões no registro de valor retornado. Examinei x86, ARM e MIPS pelo menos (em gcc.godbolt.org ), e o gcc parece se esforçar para fazer isso em-O0
. Mas lembre-se você tirar proveito disso, o idioma que você está programando-in égcc -O0
, não C , e você deve rotular a sua resposta em conformidade, não como C . Ele falha em qualquer nível de otimização que não seja o-O0
modo de depuração e não funciona com o clang IIRC.Use em
*a
vez dea[0]
para acessar o primeiro elemento de uma matriz.Os operadores relacionais (
!=
,>
, etc.) dão0
ou1
. Use isso com operadores aritméticos para fornecer compensações diferentes, dependendo se a condição for verdadeira ou falsa:a[1+2*(i<3)]
acessariaa[1]
sei >= 3
e dea[3]
outra forma.fonte
a[i<3?3:1]
é dois caracteres menor quea[1+2*(i<3)]
.Você pode procurar nos arquivos da IOCCC (concurso internacional de código C ofuscado).
Um truque notável é #definar macros cuja expansão tenha chaves / parênteses desequilibrados, como
fonte
#define P;printf(
.for(int i=0;i<n;i++){a(i);b(i);}
pode ser reduzido de algumas maneiras:for(int i=0;i<n;){a(i);b(i++);}
-1 para mover o++
para o últimoi
no loopfor(int i=0;i<n;b(i++))a(i);
-3 mais para mover tudo, exceto uma instrução, para a parte superior e para fora do loop principal, removendo as chavesfonte
Vá funcional!
Se você puder reduzir seu problema a funções simples com a mesma assinatura e definidas como expressões únicas, poderá fazer melhor que
#define r return
e fatorar quase todo o padrão para definir uma função.O resultado do programa é seu valor de status retornado ao SO ou shell de controle ou IDE.
Usar
__VA_ARGS__
permite usar o operador vírgula para introduzir pontos de sequência nessas expressões de função . Se isso não for necessário, a macro pode ser menor.fonte
use
scanf("%*d ");
para ler a entrada fictícia. (caso essa entrada não faça sentido em outro programa), é mais curta do quescanf("%d",&t);
onde você também precisa declarar a variável t.armazenar caracteres na matriz int é muito melhor que a matriz de caracteres. exemplo.
s[],t;main(c){for(scanf("%*d ");~(c=getchar());s[t++]=c)putchar(s[t]);}
fonte
%*d
não somente em Golf, porque ele também é útil em situações onde se poderia, por exemplo, querer ignorar uma nova linha emscanf("%[^\n]%*c",str);
:)Imprima um caractere e retorne o carro, em vez de:
ou
simplesmente, declare c como int e:
fonte
puts(&c)
realmente funciona? Isso não seria necessariamente nulo.char *
, vemos uma string singleton: o caractere c , seguido por um byte nulo.Usar
asprintf()
poupa a alocação explícita e também mede o comprimento de uma string akachar*
! Talvez isso não seja muito útil para o golfe com código, mas facilita o trabalho diário com matrizes de caracteres. Há mais algumas boas aconselha em 21st Century C .Exemplo de uso:
fonte
import
se você precisarConforme observado na primeira resposta , alguns compiladores (principalmente o GCC e o clang) permitem que você se omita na omissão de
#include
s para funções de biblioteca padrão.Mesmo que você não consiga apenas remover o
#include
, pode haver outras maneiras de evitá-lo , mas isso nem sempre é prático ou particularmente divertido.Nos demais casos, você pode usar em
#import<header file>
vez de#include<header file>
salvar um byte. Esta é uma extensão GNU e é considerada obsoleta, mas funciona pelo menos no gcc 4.8, no gcc 5.1 e no clang 3.7.fonte
Tente em
cpow()
vez decos()
Ao invés de
tente algo como
Isso usa a fórmula de Euler , uma análise um pouco complexa e a observação de que atribuir um complexo a um duplo produz a parte real (cuidado com as chamadas de funções variadas e outras sutilezas).
Este tipo de truque pode ser usado para reduzir
para dentro
Porque( - 1 )x2= j2 x2= jx
Edit: Equações agora inlineeuUMATEX em vez de imagens.
fonte
Aqui estão algumas dicas que eu usei para minha vantagem. Eu descaradamente os roubei de outras pessoas, então agradeço a ninguém, exceto a mim:
Combinar atribuição com chamadas de função
Em vez disso:
Fazem isto:
Inicialize várias variáveis juntas (quando possível)
Em vez disso:
Fazem isto:
Recolher valores zero / diferentes de zero
Este é um truque interessante que aprendi com alguém aqui (não lembro de quem, desculpe). Quando você tem um valor inteiro e precisa recolhê-lo para 1 ou 0, pode usá
!!
-lo com facilidade. Às vezes, isso é vantajoso para outras alternativas, como?:
.Tome esta situação:
Você poderia fazer o seguinte:
Outro exemplo:
Pode ser reescrito como:
fonte
R*-~!!mxxxx
O conhecimento de igualidades lógicas básicas pode salvar alguns bytes. Por exemplo, em vez de
if (!(a&&b)){}
tentar usar a lei de DeMorganif (!a||!b){}
. O mesmo se aplica às funções bit a bit: em vez de~(a|b)
do~a&~b
.fonte