Suggerimenti per giocare a golf in C


138

Quali consigli generali hai per giocare a golf in C? Sto cercando idee che possano essere applicate ai problemi del codice golf in generale che siano almeno in qualche modo specifiche per C (es. "Rimuovere i commenti" non è una risposta). Si prega di inviare un suggerimento per risposta. Inoltre, includi se il tuo suggerimento si applica a C89 e / o C99 e se funziona solo su alcuni compilatori.


8
Penso che il più grande suggerimento a frase singola sia: leggi i codici vincenti inviati a IOCCC.
vsz,

Risposte:


107

Utilizzare XOR bit a bit per verificare la disuguaglianza tra numeri interi:

if(a^b)invece di if(a!=b)salva 1 carattere.


73
a-bti dà lo stesso effetto.
ugoren,

22
Allo stesso modo puoi usare a*binvece di a&&b(ha una precendenza diversa, può essere o non essere male). Se conosci a / = -b (es. Non sono firmati) allora a||b==a+b
walpen

3
meglio ancora combinarlo con l'operatore Elvis ?:(anziché se): ad esempio fare qualcosa solo se diverso: a^b?_diff_:;
Olivier Dulac il

1
@OlivierDulac Esiste un compilatore che accetta un ternario vuoto se falso ramo?
Jonathan Frech,

1
@OlivierDulac Puoi controllare. Da quello che so, GCC ha un ?:operatore che equivale aa ? a : b
Chromium,

75
  • mainElenco degli argomenti degli abusi per dichiarare una o più variabili intere:

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

    (risposta a L'alfabeto nei linguaggi di programmazione )

    Questa soluzione abusa anche del fatto che a(aka argc) inizia come 1, a condizione che il programma venga chiamato senza argomenti.

  • Usa le variabili globali per inizializzare le cose a 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");}
    

    (rispondi ad Anagram Code Golf! )


62

L'operatore virgola può essere utilizzato per eseguire più espressioni in un singolo blocco evitando parentesi graffe:

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");                                                                     

}

Uscite: 1 2


Non funziona se una delle affermazioni è break.
Maxim Mikhaylov,

9
@MaxLawnboy perché breakè un'affermazione e questa risposta parla di espressioni.
NieDzejkob,

59

Evita dichiarazioni catastrofiche di tipo argomento-funzione

Se stai dichiarando una funzione in cui tutti e cinque gli argomenti sono ints, allora la vita è buona. puoi semplicemente scrivere

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

Ma supponiamo che ddebba essere un char, o addirittura un int*. Allora sei fregato! Se un parametro è preceduto da un tipo, tutti devono essere:

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

Ma aspetta! C'è un modo per aggirare questa disastrosa esplosione di personaggi inutili. Va così:

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

Ciò consente di risparmiare anche su una maindichiarazione standard se è necessario utilizzare gli argomenti della riga di comando:

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

è due byte più breve di

main(int c,char**v){

Sono stato sorpreso di scoprirlo, dal momento che non l'ho ancora incontrato su PPCG.


6
Perché mai funziona?
Nathaniel,

30
Apparentemente questo si chiama stile K&R e precede ANSI C di un decennio.
Dennis,

Nota che usare le funzioni di K&R e le nuove funzioni (diciamo '99) insieme no o potrebbe non essere possibile. Dipende dal tuo compilatore.
dmckee,

5
@dmckee ha ragione. C99 non consente l'int implicito, quindi devi usare -std=gnu99e ora non sei portatile. In clc-speak, non stai nemmeno scrivendo il codice "C" in sé, ma "Gnu99-C". 'Qui intorno lo ignoriamo principalmente, ma è bene menzionarlo se pubblichi un codice specifico del compilatore. A volte la gente in realtà non scaricare ed eseguire questi programmi della nostra. :)
luser droog

@luserdroog: puoi usare -std=c89per dire a gcc o clang di compilare il tuo codice in base a quello standard precedente, il che consente un int implicito solo con un avvertimento.
Peter Cordes,

37

Invece di> = e <= puoi semplicemente usare la divisione intera (/) quando i valori confrontati sono sopra lo zero, il che salva un carattere. Per esempio:

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

Il che è ovviamente ancora restringibile, usando ad esempio solo> e ^ (un modo intelligente per evitare di scrivere && o || in alcuni casi).

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

Il trucco della divisione di numeri interi è utile, ad esempio, per decidere se un numero è inferiore a 100, in quanto ciò salva un carattere:

a<100 vs 99/a

Ciò è positivo anche nei casi in cui è necessaria una precedenza maggiore.


Puoi scrivereputchar(c>31&c<127?c:46);
Jin X

37

Alcuni compilatori, come GCC, consentono di omettere #includei tipi di base s, param e return per main.

Di seguito è riportato un programma C89 e C99 valido che viene compilato (con avvisi) con GCC:

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

Si noti che #includefor stdio.h è mancante, manca il tipo restituito per maine manca la dichiarazione del tipo per i.


17
Tecnicamente non è valido secondo gli standard poiché main accetta zero o due parametri, non uno. Non che a nessuno importa del codice golf.
Konrad Borowski il

La chiamata printf()(o qualsiasi funzione variadica) senza un prototipo provoca un comportamento indefinito . GCC non compila lo standard C per impostazione predefinita. Se invochi gcc in modalità C89 ( gcc -ansi -pedantic) o C99 ( gcc -std=c99 -pedantic), riceverai parecchi reclami, almeno in quest'ultimo caso.
Nisse Engström,

@ NisseEngström: le convenzioni di chiamata sulle implementazioni C tradizionali rendono sicuro chiamare funzioni variadiche senza prototipi. Quindi la maggior parte delle implementazioni in C definisce il comportamento.
Peter Cordes,

29

L'operatore condizionale ternario ?:spesso può essere utilizzato come uno stand in per semplici if- elsele dichiarazioni a un notevole risparmio.

A differenza dell'equivalente c ++ l'operatore non fornisce formalmente un valore , ma alcuni compilatori (in particolare gcc) ti permetteranno di cavartela , il che è un bel bonus.


Aggiunta: se hai solo bisogno di un if, ma non di un altro, il ternario può ancora essere utile.
Casey,

9
&&e ||può anche essere usato: if(x==3)f()diventa con il tuo suggerimento x==3?f():0e può essere ulteriormente migliorato x==3&&f(). Ma fai attenzione con la precedenza dell'operatore: se f()viene sostituita con y=1, la &&soluzione richiede un set di parentesi aggiuntivo.
ugoren,

1
Non mi ero mai reso conto che GCC ?:produce un valore. Posso usarlo nel codice di produzione? lol
Jeff Burdges,

4
@ugoren: x==3&&f()può essere ulteriormente giocato ax^3||f()
fgrieu il

@fgrieu, sì, anche se non è esattamente l'argomento qui ( questa risposta lo suggerisce).
ugoren,

27

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

I bit sono carini.

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

Ma con precedenti diverse e non modificare x come ++ e -. Inoltre puoi usarlo in casi davvero specifici: ~ 9 è più corto di -10.

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

È più esoterico, ma ho avuto occasione di usarlo. Se non ti interessa il corto circuito

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

Anche:

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

5
L'ultimo suggerimento ( (x/y) == (x>=y)) è davvero utile.
ugoren,

24

Usa lambda (non portabile)

Invece di

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

o (solo gcc)

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

oppure (llvm con supporto dei blocchi)

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

prova qualcosa del genere

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

... dove la stringa tra virgolette contiene le istruzioni del linguaggio macchina della funzione "lambda" (conforme a tutti i requisiti ABI della piattaforma).

Funziona in ambienti in cui le costanti di stringa sono contrassegnate come eseguibili. Per impostazione predefinita, questo è vero in Linux e OSX ma non in Windows.

Un modo sciocco per imparare a scrivere le tue funzioni "lambda" è scrivere la funzione in C, compilarla, ispezionarla con qualcosa di simile objdump -De copiare il corrispondente codice esadecimale in una stringa. Per esempio,

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

... quando compilato gcc -Os -cper un target x86_64 di Linux genera qualcosa di simile

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

GNU CC goto:

Puoi chiamare queste "funzioni lambda" direttamente ma se il codice che stai chiamando non accetta parametri e non restituirà, puoi usare gotoper salvare qualche byte. Quindi invece di

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

o (se il tuo ambiente non ha glifi arabi)

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

Provare

goto*&L"ﻫ";

o

goto*&L"\xfeeb";

In questo esempio, eb feè il linguaggio macchina x86 per qualcosa di simile for(;;);ed è un semplice esempio di qualcosa che non accetta parametri e non restituirà :-)

Si scopre che è possibile gotocodificare che ritorna a un genitore chiamante.

#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));
}

L'esempio sopra (potrebbe essere compilato ed eseguito su Linux con gcc -O) è sensibile al layout dello stack.

EDIT: a seconda della tua toolchain, potresti dover usare il -zexecstackflag di compilazione.

Se non è immediatamente evidente, questa risposta è stata scritta principalmente per i lols. Non mi assumo alcuna responsabilità per il golf migliore o peggiore o per risultati psicologici avversi dalla lettura di questo.


2
Ho appena scritto una sceneggiatura per leggere parti di una funzione C dallo standard in e stampare una C lambda. Potrebbe valere la pena menzionarlo nella tua risposta, potrebbe essere bello da vedere perché mi hai insegnato a farlo in primo luogo.
MD XF,

23

Usa i cursori anziché i puntatori. Afferra brk()all'inizio e usalo come un puntatore di base .

char*m=brk();

Quindi crea un #define per l'accesso alla memoria.

#define M [m]

Mdiventa un postfisso *applicato agli interi. (Il vecchio trucco di [x] == x [a].)

Ma c'è di più! Quindi puoi avere argomenti puntatore e ritorni in funzioni più brevi delle macro (specialmente se abbrevia "ritorno"):

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

Per creare un cursore da un puntatore, sottrai il puntatore di base, producendo un ptrdiff_t, che si tronca in un int, le perdite sono il tuo biz.

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

Questa tecnica viene utilizzata nella mia risposta a Scrivere un interprete per il calcolo lambda non tipizzato .


21

Definire i parametri anziché le variabili.

f(x){int y=x+1;...}

f(x,y){y=x+1;...}

Non è necessario passare effettivamente il secondo parametro.

Inoltre, è possibile utilizzare la precedenza dell'operatore per salvare la parentesi.
Ad esempio, (x+y)*2può diventare x+y<<1.


O semplicemente x+y*2, risparmiando ancora un altro carattere.
Braden Best

4
@ B1KMusic, x+y*2non è lo stesso, a causa della precedenza dell'operatore.
ugoren,

Bene, lol. Sarebbe x + (y * 2). Sono stato fissato x+y<<1sull'esempio, supponendo che fosse valutato come x+(y<<1), e suggerivo *2invece. Non sapevo che le operazioni di bitshift fossero valutate come ad es(x+y)<<2
Braden Best

20

Dal momento che di solito EOF == -1, utilizzare il NOT bit a bit all'operatore di verificare la presenza di EOF: while(~(c=getchar()))o while(c=getchar()+1)e modificare il valore di c in ogni luogo


1
Non conosco abbastanza bene C, ma non while(1+c=getchar())funzionerebbe?
ɐɔıʇǝɥʇuʎs

6
@ ɐɔıʇǝɥʇuʎs No. L'operatore addizione +ha una precedenza maggiore rispetto all'operatore assegnazione =, quindi 1+c=getchar()equivale a (1+c)=getchar(), che non viene compilato perché (1+c)non è un valore.
ace_HongKongIndipendenza

19

L'operatore ternario ?:è insolito in quanto ha due pezzi separati. Per questo motivo, fornisce un po 'di scappatoia alle regole di precedenza dell'operatore standard. Questo può essere utile per evitare le parentesi.

Prendi il seguente esempio:

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

Il solito approccio al golf è quello di sostituire il ifcon &&, ma a causa della bassa precedenza dell'operatore virgola, è necessario un paio di parentesi extra:

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

La sezione centrale dell'operatore ternario non ha bisogno di parentesi, tuttavia:

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

Commenti simili si applicano agli indici di array.


7
In questo esempio, b-=a=bè ancora più breve. Il ?:trucco è ancora utile, -=perché ha anche una bassa preferenza.
ugoren

Buon punto; il mio esempio era inutilmente complesso.
breadbox

Un altro punto è che a volte si desidera capovolgere la condizione: per x>0||(y=3), x>0?0:(y=3)è inutile, ma x<1?y=3:0non il lavoro.
ugoren

sia clang che gcc consentono un vero caso vuoto nel ternario. Se omesso, il suo valore è il valore della condizione. Ad esempio,x>5?:y=1
Chris Uzdavinis,

19

Qualsiasi parte del codice che si ripete più volte può essere sostituita con il pre-processore.

#define R return

è un caso d'uso molto comune se il codice prevede più di un paio di funzioni. Altre parole chiave piuttosto lunghe come while, double, switche casesono anche candidati; così come tutto ciò che è idomatico nel tuo codice.

In genere, riservo il carattere maiuscolo a questo scopo.


1
Una sostituzione più breve sarebbe -DR=return. Si noti che se si includono determinati caratteri, potrebbe essere necessario avere virgolette singole o doppie attorno alla definizione -DP='puts("hello")'.

15

Se il tuo programma sta leggendo o scrivendo su uno in ogni passaggio, prova sempre a usare la funzione di lettura e scrittura invece di getchar () e putchar () .

Esempio ( Inverti stdin e posiziona su stdout )

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

Esercizio: usa questa tecnica per ottenere un buon punteggio qui .


Cosa intendi per ogni passo ?
Casey,

Casey: immagino significhino se il programma sta leggendo qualcosa, ci opera e scrive l'output. In modo streaming, per così dire. Al contrario di un approccio in cui tutti gli input devono essere letti e gestiti contemporaneamente.
Joey,

Joey ha ragione, intendevo lo stesso, mi spiace di non aver controllato la posta in arrivo fino ad oggi.
Quixotic,

8
La manipolazione dello stack è meravigliosa.
Andrea Biondo,

14

Cicli inversi

Se puoi, prova a sostituire

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

con

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


12

Usa i valori di ritorno a zero roba. Se si chiama una funzione e tale funzione restituisce zero in condizioni normali, è possibile posizionarla in una posizione in cui è previsto zero. Allo stesso modo se sai che la funzione restituirà un valore diverso da zero, con l'aggiunta di un botto. Dopotutto, in ogni caso non si esegue correttamente la gestione degli errori in un codice golf, giusto?

Esempi:

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

12

Assegna invece di restituire.

Questo non è proprio lo standard C, ma funziona con ogni compilatore e CPU che conosco:

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

ha lo stesso effetto di:

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

Perché il primo argomento è archiviato nello stesso registro CPU del valore restituito.

Nota: come indicato in un commento, si tratta di un comportamento indefinito e non è garantito che funzioni per ogni operazione. E qualsiasi ottimizzazione del compilatore lo salterà.

X-Macro

Un'altra utile funzione: X-Macro può aiutarti quando hai un elenco di variabili e devi fare alcune operazioni che coinvolgono tutte:

https://en.wikipedia.org/wiki/X_Macro


3
L'ho citato e sono stato corretto, semplicemente non è vero. Funzionerà solo con moltiplicazioni e divisioni e quando le ottimizzazioni sono disattivate. Questo perché entrambe le operazioni mettono i loro risultati in eax, che è il registro comune per il ritorno. I parametri sono memorizzati nello stack o ecx o edx. Prova tu stesso.
Gaspa79,

3
Hai ragione, è un comportamento indefinito, dipende anche dal compilatore e dall'architettura, di solito controllo con gcc su x86 e armv7 prima di pubblicare qualsiasi risposta usando questo trucco. E ovviamente se abiliti l'ottimizzazione, qualsiasi compilatore intelligente eliminerebbe semplicemente la moltiplicazione non necessaria.
GB

3
Ho visto questo lavoro con GCC ma non con altri
Albert Renshaw,

1
@ Gaspa79: gcc -O0sceglie sempre di valutare le espressioni nel registro del valore restituito. Ho esaminato almeno x86, ARM e MIPS (su gcc.godbolt.org ), e gcc sembra fare di tutto per farlo -O0. Ma ricordate, se si prende vantaggio di questa, la lingua che si sta programmando in è gcc -O0, non C , e si dovrebbe etichettare la tua risposta di conseguenza, non come C . Non funziona a nessun livello di ottimizzazione diverso dalla -O0modalità di debug e non funziona con clang IIRC.
Peter Cordes,

11
  1. Utilizzare *ainvece di a[0]per accedere al primo elemento di un array.

  2. Gli operatori relazionali ( !=, >, ecc) danno 0o 1. Usalo con operatori aritmetici per fornire offset diversi a seconda che la condizione sia vera o falsa: a[1+2*(i<3)]accederebbe a[1]se i >= 3e a[3]altrimenti.


11
a[i<3?3:1]è due caratteri più corto di a[1+2*(i<3)].
Reto Koradi,

10

Puoi consultare gli archivi IOCCC (concorso internazionale per codice C offuscato).

Un trucco notevole è #definire le macro la cui espansione ha parentesi / parentesi sbilanciate, come

#define P printf(

16
Le parentesi non corrispondenti non hanno alcun valore in se stesse. Il punto è definire il più possibile lo schema ripetitivo. Potresti voler andare oltre, con #define P;printf(.
ugoren

Come conta questo accorciare i byte? Forse fornire un esempio?
Cyoce,

2
@Cyoce Vedi ad esempio questa risposta .
Jonathan Frech,

8

for(int i=0;i<n;i++){a(i);b(i);} può essere ridotto in alcuni modi:

for(int i=0;i<n;){a(i);b(i++);} -1 per spostare ++l'ultimo inell'anello

for(int i=0;i<n;b(i++))a(i); -3 in più per spostare tutte le istruzioni tranne una nella parte superiore e all'esterno del ciclo principale, rimuovendo le parentesi graffe


L'uso dell'operatore virgola è un altro modo per evitare le parentesi graffe in alcuni casi.
Peter Cordes,

8

Diventa funzionale!

Se riesci a ridurre il tuo problema a funzioni semplici con la stessa firma e definite come singole espressioni, puoi fare meglio di #define r returne fattorizzare quasi tutto il boilerplate per definire una funzione.

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

Il risultato del programma è il valore dello stato restituito al sistema operativo o controllo shell o IDE.

L'utilizzo __VA_ARGS__consente di utilizzare l'operatore virgola per introdurre punti di sequenza in queste espressioni di funzioni . Se ciò non è necessario, la macro può essere più breve.

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

7
  1. usare scanf("%*d ");per leggere l'ingresso fittizio. (nel caso in cui l'input non abbia senso in un ulteriore programma) è più breve di scanf("%d",&t);dove è necessario dichiarare anche la variabile t.

  2. la memorizzazione dei caratteri nella matrice int è molto meglio della matrice dei caratteri. esempio.

    s[],t;main(c){for(scanf("%*d ");~(c=getchar());s[t++]=c)putchar(s[t]);}


2
In realtà, non uso %*dsolo nel golf perché è utile anche in situazioni in cui si vorrebbe, ad esempio, saltare una nuova riga in scanf("%[^\n]%*c",str);:)
tomsmeding,

6

Stampa un carattere e poi ritorno a capo, invece di:

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

o

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

semplicemente, dichiarare c come int e:

puts(&c);

9
Vale probabilmente la pena sottolineare che questo dipende da un'architettura little-endian. Se c è un int big-endian, otterrai solo il ritorno a capo. (D'altra parte, se c è un carattere, potresti ottenere spazzatura casuale dopo invece di un ritorno a
capo

@breadbox sì, hai perfettamente ragione; Ho appena modificato: l'ultimo estratto dovrebbe usare c come int (che è spesso facile da dichiarare come tale).
Moala,

Funziona puts(&c)davvero? Ciò non sarebbe necessariamente terminato con null.
Esolanging Fruit

1
@EsolangingFruit Su little-endian con ints a 32 bit, un int 0 ≤ c <256 viene memorizzato come sequenza di byte c 0 0 0 . Quando interpretiamo l'indirizzo di c as char *, vediamo una stringa singleton: il carattere c , seguito da un byte null.
Dennis,

6

L'utilizzo asprintf()consente di risparmiare l'allocazione esplicita e anche la misurazione della lunghezza di una stringa aka char*! Questo non è forse troppo utile per giocare a golf, ma facilita il lavoro quotidiano con un array di caratteri. Ci sono altre buone consiglia nella 21 ° secolo C .

Esempio di utilizzo:

#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 devi

Come notato nella prima risposta , alcuni compilatori (in particolare GCC e clang) consentono di evitare #includele funzioni di libreria standard.

Anche se non puoi semplicemente rimuoverlo #include, potrebbero esserci altri modi per evitarlo , ma non è sempre pratico o particolarmente da golf.

Nei restanti casi, è possibile utilizzare #import<header file>invece di #include<header file>salvare un byte. Questa è un'estensione GNU ed è considerata obsoleta, ma funziona almeno in gcc 4.8, gcc 5.1 e clang 3.7.


6

Prova cpow()invece dicos()

Invece di

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

prova qualcosa del genere

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

Questo utilizza la formula di Eulero , un'analisi un po 'complessa e l'osservazione che l'assegnazione di un complesso a un doppio produce la parte reale (attenta alle chiamate di funzioni variadiche e ad altre sottigliezze).

cos2πx+jsin2πx=ej2πx=ejπ2x=(1)2x

Questo tipo di trucco può essere utilizzato per ridurre

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

dentro, come moto a luogo, andare da dentro a fuori: I put my hand inTO my pocket = metto la mano in tasca

double y=cpow(1i,x);

(1)x2=j2x2=jx

LATEX


5

Ecco alcuni suggerimenti che ho usato a mio vantaggio. Li ho spudoratamente rubati agli altri, quindi merito a chiunque tranne me:

Combina l'assegnazione con le chiamate di funzione

Invece di questo:

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

Fai questo:

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

Inizializza più variabili insieme (quando possibile)

Invece di questo:

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

Fai questo:

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

Comprimi valori zero / diversi da zero

Questo è un trucco che ho raccolto da qualcuno qui (non ricordo chi, scusa). Quando hai un valore intero e devi comprimerlo a 1 o 0, puoi usarlo !!per farlo facilmente. Questo a volte è vantaggioso per altre alternative come ?:.

Prendi questa situazione:

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

Potresti invece fare questo:

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

Un altro esempio:

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

Potrebbe essere riscritto come:

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

1
forseR*-~!!mxxxx
l4m2

5

Conoscere le uguaglianze logiche di base potrebbe essere in grado di salvare un paio di byte. Ad esempio, invece di if (!(a&&b)){}provare invece a usare la legge di DeMorgan if (!a||!b){}. Lo stesso vale per le funzioni bit a bit: invece di ~(a|b)do ~a&~b.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.