Dicas para jogar golfe em C


137

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.


8
Eu acho que a maior dica de frase única é: Leia os códigos vencedores enviados à IOCCC.
vsz

Respostas:


107

Use o XOR bit a bit para verificar a desigualdade entre números inteiros:

if(a^b)em vez de if(a!=b)salvar 1 caractere.


73
a-bdá o mesmo efeito.
ugoren

22
Da mesma forma, você pode usar em a*bvez de a&&b(tem precedência diferente, pode ou não ser ruim). Se você sabe a / = -b (por exemplo, eles são sem sinal), então a||b==a+b
walpen

3
melhor ainda combiná-lo com o Elvis Operator ?:(em vez de se): por exemplo, fazer apenas algo se for diferente: a^b?_diff_:;
Olivier Dulac

11
@OlivierDulac Existe um compilador que aceita uma ramificação ternária se falsa vazia?
Jonathan Frech

11
@OlivierDulac Você pode conferir. Pelo que sei, o GCC tem um ?:operador que é apenas equivalente aa ? a : b
Chromium

75
  • mainLista de argumentos do abuso para declarar uma ou mais variáveis ​​inteiras:

    main(a){for(;++a<28;)putchar(95+a);}
    

    (responda a O alfabeto nas linguagens de programação )

    Essa solução também abusa do fato de que a(aka argc) inicia como 1, desde que o programa seja chamado sem argumentos.

  • Use variáveis ​​globais para inicializar as coisas para zero:

    t[52],i;main(c){for(;i<52;)(c=getchar())<11?i+=26:t[i+c-97]++;
    for(i=27;--i&&t[i-1]==t[i+25];);puts(i?"false":"true");}
    

    (resposta a Anagram Code Golf! )


62

O operador vírgula pode ser usado para executar várias expressões em um único bloco, evitando chaves:

main(){                                                                                     

int i = 0;                                                                                  
int j = 1;                                                                                  
if(1)                                                                                       
    i=j,j+=1,printf("%d %d\n",i,j); // multiple statements are all executed                                                  
else                                                                                        
    printf("failed\n");                                                                     

}

Saídas: 1 2


Não funciona se uma das instruções for break.
precisa saber é o seguinte

9
@ MaxLawnboy porque breaké uma afirmação, e esta resposta está falando sobre expressões.
NieDzejkob

59

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 ints, a vida é boa. você pode simplesmente escrever

f(a,b,c,d,e){

Mas suponha dque seja um char, ou mesmo um int*. Então você está ferrado! Se um parâmetro for precedido por um tipo, todos eles deverão ser:

f(int a,int b,int c,int*d,int e){

Mas espere! Existe uma maneira de contornar essa explosão desastrosa de personagens inúteis. É assim:

f(a,b,c,d,e) int *d; {

Isso economiza em uma maindeclaração padrão se você precisar usar os argumentos da linha de comando:

main(c,v)char**v;{

é dois bytes menor que

main(int c,char**v){

Fiquei surpreso ao descobrir isso, pois ainda não o encontrei no PPCG.


6
Por que diabos isso funciona?
Nathaniel

30
Aparentemente, isso é chamado de estilo K&R e precede o ANSI C em uma década.
Dennis

Observe que o uso dos recursos K&R e dos recursos mais novos (por exemplo, 99) juntos não é possível ou não. Depende do seu compilador.
dmckee

5
@dmckee está certo. O C99 não permite int implícito, então você precisa usar -std=gnu99e 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. :)
luser Droog

@luserdroog: Você pode -std=c89dizer 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.
22818 Peter Cordes

37

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:

putchar(c/32&&126/c?c:46); //Prints the character, but if it is unprintable print "."

O que, é claro, ainda é reduzido, usando, por exemplo, just> e ^ (uma maneira inteligente de evitar escrever && ou || em alguns casos).

putchar(c>31^c>126?c:46);

O truque da divisão inteira é, por exemplo, útil para decidir se um número é menor que 100, pois isso salva um caractere:

a<100 vs 99/a

Isso também é bom nos casos em que é necessária maior precedência.


Você pode escreverputchar(c>31&c<127?c:46);
Jin X

37

Certos compiladores, como o GCC, permitem omitir #includetipos básicos s, param e return para main.

A seguir, é apresentado um programa C89 e C99 válido que compila (com avisos) o GCC:

main(i) { printf("%d", i); }

Observe que o #includefor stdio.h está ausente, o tipo de retorno para mainestá ausente e a declaração de tipo iestá ausente.


17
Tecnicamente, não é válido de acordo com os padrões, já que main aceita zero ou dois parâmetros, não um. Não que alguém se importe com código de golfe.
precisa saber é o seguinte

Chamar 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.
Nisse Engström

@ NisseEngström: as convenções de chamada nas principais implementações de C tornam seguro chamar funções variadas sem protótipos. Portanto, a maioria das implementações em C define o comportamento.
Peter Cordes

29

O operador condicional ternário ?:muitas vezes pode ser usado como um carrinho na de simples if- elsedeclaraçõ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.


Adição: se você precisar apenas de um if, mas não de outro, o ternário ainda poderá ser útil.
Casey

9
&&e ||também pode ser usado: if(x==3)f()fica com a sua sugestão x==3?f():0e pode ser melhorado ainda mais para x==3&&f(). Mas tenha cuidado com a precedência do operador - se f()for substituído por y=1, a &&solução requer um conjunto extra de parênteses.
ugoren

11
Eu nunca tinha percebido que o gcc ?:produz um valor l. Posso usar isso no código de produção? lol
Jeff Burdges

4
@ugoren: x==3&&f()pode ser ainda mais x^3||f()
jogado

@ Fgrieu, sim, embora não seja exatamente o tópico aqui ( esta resposta sugere).
ugoren

27

http://graphics.stanford.edu/~seander/bithacks.html

Bits são bons.

~-x = x - 1
-~x = x + 1

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.

if(!(x&y)) x | y == x ^ y == x + y
if(!(~x&y)) x ^ y == x - y

Isso é mais esotérico, mas tive ocasião de usá-lo. Se você não se importa com curtos-circuitos

x*y == x && y
if(x!=-y) x+y == x || y

Além disso:

if(x>0 && y>0) x/y == x>=y   

5
A última dica ( (x/y) == (x>=y)) é realmente útil.
ugoren

24

Use lambdas (não portável)

Ao invés de

f(int*a,int*b){return*a>*b?1:-1;}
...
qsort(a,b,4,f);

ou (somente GCC)

qsort(a,b,4,({int L(int*a,int*b){a=*a>*b?1:-1;}L;}));

ou (llvm com suporte a blocos)

qsort_b(a,b,4,^(const void*a,const void*b){return*(int*)a>*(int*)b?1:-1;});

tente algo como

qsort(a,b,4,"\x8b\7+\6\xc3");

... 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 -De copiar o código hexadecimal correspondente em uma string. Por exemplo,

int f(int*a, int*b){return *a-*b;}

... quando compilado gcc -Os -cpara um destino Linux x86_64 gera algo como

0:   8b 07                   mov    (%rdi),%eax
2:   2b 06                   sub    (%rsi),%eax
4:   c3                      retq

GNU 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 gotopara salvar alguns bytes. Então, ao invés de

((int(*)())L"ﻫ")();

ou (se o seu ambiente não tiver glifos em árabe)

((int(*)())L"\xfeeb")();

Experimentar

goto*&L"ﻫ";

ou

goto*&L"\xfeeb";

Neste exemplo, eb feé a linguagem de máquina x86 para algo como for(;;);e é um exemplo simples de algo que não aceita parâmetros e não retorna :-)

Acontece que você pode gotocodificar que retorna para um pai que está chamando.

#include<stdio.h>
int f(int a){
 if(!a)return 1;
 goto*&L"\xc3c031"; // return 0;
 return 2; // never gets here
}
int main(){
 printf("f(0)=%d f(1)=%d\n",f(0),f(1));
}

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 -zexecstacksinalizador 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.


2
Acabei de escrever um script para ler partes de uma função C do padrão e imprimir uma lambda C. Pode valer a pena mencionar na sua resposta, pode ser bom para você ver, já que me ensinou a fazer isso em primeiro lugar.
MD XF

23

Use cursores em vez de ponteiros. Pegue o brk()no início e use-o como um ponteiro de base .

char*m=brk();

Em seguida, faça um #define para acesso à memória.

#define M [m]

Mtorna-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'):

f(x){return x M;} //implicit ints, but they work like pointers
#define f(x) (x M)

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.

char *p = sbrk(sizeof(whatever)) - m;
strcpy(m+p, "hello world");

Essa técnica é usada na minha resposta para Escrever um intérprete para o cálculo lambda sem tipo .


21

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)*2pode se tornar x+y<<1.


Ou apenas x+y*2, salvando mais um caractere.
Braden Best

4
@ B1KMusic, x+y*2não é o mesmo, devido à precedência do operador.
precisa saber é o seguinte

Certo, lol. Isso seria x + (y * 2). Eu estava fixo no x+y<<1exemplo, supondo que ele estivesse sendo avaliado como x+(y<<1)e sugeri o *2contrário. Eu não sabia operações bitshift foram avaliadas como por exemplo(x+y)<<2
Braden Melhor

20

Como geralmente EOF == -1, use o operador NOT bit a bit para verificar o EOF: while(~(c=getchar()))ou while(c=getchar()+1)e modifique o valor de c em todos os lugares


11
Não conheço C o suficiente, mas não while(1+c=getchar())funcionaria?
ɐɔıʇǝɥʇuʎs

6
Não. O operador de adição +tem precedência mais alta que o operador de atribuição =, portanto 1+c=getchar()é equivalente a (1+c)=getchar(), que não é compilado porque (1+c)não é um valor l.
ace_HongKongIndependence

19

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:

if (t()) a = b, b = 0;  /* 15 chars */

A abordagem usual do golfe é substituir ifpor &&, mas devido à baixa precedência do operador de vírgula, você precisa de um par extra de parênteses:

t() && (a = b, b = 0);  /* still 15 chars */

A seção do meio do operador ternário não precisa de parênteses, no entanto:

t() ? a = b, b = 0 : 0;  /* 14 chars */

Comentários semelhantes se aplicam aos subscritos da matriz.


7
Neste exemplo, b-=a=bé ainda mais curto. O ?:truque ainda é útil, -=porque também tem pouca preferência.
Ugoren

Bom ponto; meu exemplo foi desnecessariamente complexo.
breadbox

Outro ponto é que às vezes você quer mudar a condição: pois x>0||(y=3), x>0?0:(y=3)é inútil, mas x<1?y=3:0faz o trabalho.
Ugoren

clang e gcc permitem um caso verdadeiro vazio no ternário. Se omitido, seu valor é o valor da condição. Por exemplo,x>5?:y=1
Chris Uzdavinis

19

Qualquer parte do seu código que se repita várias vezes é candidata à substituição pelo pré-processador.

#define R return

é 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, e casetambém são candidatos; bem como tudo o que é idomatic no seu código.

Geralmente, reservo caracteres maiúsculos para esse fim.


11
Uma substituição mais curta seria -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")'.

15

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 )

main(_){write(read(0,&_,1)&&main());}

Exercício: Use esta técnica para obter uma boa pontuação aqui .


O que você quer dizer com cada etapa da etapa ?
Casey

Casey: Eu acho que eles querem dizer se o programa está lendo alguma coisa, opera nele e escreve a saída. De maneira fluida, por assim dizer. Ao contrário de uma abordagem em que toda a entrada deve ser lida e tratada de uma só vez.
Joey

Joey está certo, eu quis dizer o mesmo, desculpe por não ter checado minha caixa de entrada até hoje.
Quixotic

8
Essa manipulação de pilha é maravilhosa.
Andrea Biondo

14

Loops Reversos

Se puder, tente substituir

for(int i=0;i<n;i++){...}

com

for(int i=n;i--;){...}


12

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:

close(fd);foo=0;   →  foo=close(fd);    /* saves two bytes */
putchar(c);bar=0;  →  bar=!putchar(c);  /* saves one byte  */

12

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:

int sqr(int a){return a*a;}

tem o mesmo efeito que:

int sqr(int a){a*=a;}

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


3
Eu citei isso e fui corrigido, isso simplesmente não é verdade. Ele funcionará apenas com multiplicações e divisões e quando as otimizações estiverem desativadas. Isso ocorre porque as duas operações colocam seus resultados em eax, que é o registro comum para retorno. Os parâmetros são armazenados na pilha ou ecx ou edx. Tente você mesmo.
Gaspa79

3
Você está certo, é um comportamento indefinido, também depende do compilador e da arquitetura. Costumo verificar com o gcc no x86 e no armv7 antes de postar qualquer resposta usando esse truque. E, claro, se você ativar a otimização, qualquer compilador inteligente excluiria a multiplicação desnecessária.
GB

3
Eu já vi esse trabalho no GCC, mas não em outros
Albert Renshaw

11
@ Gaspa79: o gcc -O0sempre 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 -O0modo de depuração e não funciona com o clang IIRC.
Peter Cordes

11
  1. Use em *avez de a[0]para acessar o primeiro elemento de uma matriz.

  2. Os operadores relacionais ( !=, >, etc.) dão 0ou 1. 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] se i >= 3e de a[3]outra forma.


11
a[i<3?3:1]é dois caracteres menor que a[1+2*(i<3)].
Reto Koradi

10

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

#define P printf(

16
Os parênteses incompatíveis não têm valor em si mesmos. O objetivo é definir o máximo possível do padrão de repetição. Você pode querer ir mais longe, com #define P;printf(.
Ugoren

Como isso reduz a contagem de bytes? Talvez dê um exemplo?
precisa saber é o seguinte

2
@Cyoce Veja, por exemplo, esta resposta .
31818 Jonathan Frech

8

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 último ino loop

for(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 chaves


O uso do operador de vírgula é outra maneira de evitar chaves em alguns casos.
Peter Cordes

8

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 returne fatorar quase todo o padrão para definir uma função.

#define D(f,...)f(x){return __VA_ARGS__;}
D(f,x+2)
D(g,4*x-4)
D(main,g(4))

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.

#define D(f,b)f(x){return b;}

7
  1. use scanf("%*d ");para ler a entrada fictícia. (caso essa entrada não faça sentido em outro programa), é mais curta do que scanf("%d",&t);onde você também precisa declarar a variável t.

  2. 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]);}


2
Na verdade, eu uso %*dnão somente em Golf, porque ele também é útil em situações onde se poderia, por exemplo, querer ignorar uma nova linha em scanf("%[^\n]%*c",str);:)
tomsmeding

6

Imprima um caractere e retorne o carro, em vez de:

printf("%c\n",c);

ou

putchar(c);putchar('\n'); // or its ascii value, whatever!

simplesmente, declare c como int e:

puts(&c);

9
Provavelmente, vale ressaltar que isso depende de uma arquitetura little-endian. Se c é um int big-endian, você receberá o retorno de carro. (Por outro lado, se c é um char, você pode ter lixo aleatório depois, em vez de um retorno de carro.)
breadbox

@breadbox sim, você está totalmente certo; Acabei de editar: o último trecho deve usar c como int (o que é fácil de declarar como tal).
moala

Será que puts(&c)realmente funciona? Isso não seria necessariamente nulo.
Esolanging Fruit

11
@EsolangingFruit No little endian com entradas de 32 bits, um int 0 ≤ c <256 é armazenado como a sequência de bytes c 0 0 0 . Ao interpretar o endereço de c as char *, vemos uma string singleton: o caractere c , seguido por um byte nulo.
Dennis

6

Usar asprintf()poupa a alocação explícita e também mede o comprimento de uma string aka char*! 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:

#define _GNU_SOURCE
#include <stdio.h>

int main(int argc, char** argv) {
  char* foo;
  asprintf(&foo, "%s", argv[1]);
  printf("%s",foo);
}

6

import se você precisar

Conforme observado na primeira resposta , alguns compiladores (principalmente o GCC e o clang) permitem que você se omita na omissão de #includes 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.


6

Tente em cpow()vez decos()

Ao invés de

double y=cos(M_PI*2*x);

tente algo como

double y=cpow(-1,x*2);

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).

porque2πx+jpecado2πx=ej2πx=ejπ2x=(-1 1)2x

Este tipo de truque pode ser usado para reduzir

double y=cpow(-1,x/2);

para dentro

double y=cpow(1i,x);

Porque (-1 1)x2=j2x2=jx

Edit: Equações agora inline euUMATEX em vez de imagens.


5

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:

r = /* Some random expression */
printf("%d", r);

Fazem isto:

printf("%d", r = /* Some random expression */);

Inicialize várias variáveis ​​juntas (quando possível)

Em vez disso:

for(i=0,j=0;...;...){ /* ... */ }

Fazem isto:

for(i=j=0;...;...){ /* ... */ }

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:

n=2*n+isupper(s[j])?1:0; /* 24 */

Você poderia fazer o seguinte:

n=n*2+!!isupper(s[j]); /* 22 */

Outro exemplo:

r=R+(memcmp(b+6,"---",3)?R:0); /* 30 */

Pode ser reescrito como:

r=R+R*!!memcmp(b+6,"---",3)); /* 29 */

11
talvezR*-~!!mxxxx
l4m2 18/04/19

5

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 DeMorgan if (!a||!b){}. O mesmo se aplica às funções bit a bit: em vez de ~(a|b)do ~a&~b.


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.