Quels conseils généraux avez-vous pour jouer au golf en C? Je recherche des idées pouvant être appliquées aux problèmes de code de golf en général, qui sont au moins quelque peu spécifiques à C (par exemple, "supprimer les commentaires" n'est pas une réponse). Merci de poster un pourboire par réponse. Indiquez également si votre conseil s’applique à C89 et / ou C99 et s’il ne fonctionne que sur certains compilateurs.
138
Réponses:
Utilisez le bitor XOR pour vérifier l’inégalité entre les entiers:
if(a^b)
au lieu deif(a!=b)
sauvegarder 1 caractère.la source
a-b
vous donne le même effet.a*b
au lieu dea&&b
(a une précédence différente, peut être ou ne pas être mauvais). Si vous connaissez un / = -b (par exemple, ils ne sont pas signés), alorsa||b
==a+b
?:
(au lieu de if): par exemple pour faire quelque chose si différent:a^b?_diff_:;
?:
opérateur qui équivaut juste àa ? a : b
main
Liste des arguments abusifs pour déclarer une ou plusieurs variables entières:(réponse à l'alphabet dans les langages de programmation )
Cette solution abuse également du fait que
a
(akaargc
) commence comme1
, à condition que le programme soit appelé sans arguments.Utilisez des variables globales pour initialiser les éléments à zéro:
(réponse à Anagram Code Golf! )
la source
L'opérateur de virgule peut être utilisé pour exécuter plusieurs expressions dans un seul bloc tout en évitant les accolades:
Les sorties:
1 2
la source
break
.break
est une déclaration, et cette réponse parle d'expressions.Évitez les déclarations catastrophiques de type argument de fonction
Si vous déclarez une fonction où les cinq arguments sont tous des
int
s, la vie est belle. vous pouvez simplement écrireMais supposons que ce
d
soit unchar
, voire unint*
. Alors vous êtes foutu! Si un paramètre est précédé d'un type, tous doivent être:Mais attendez! Il y a un moyen de contourner cette explosion désastreuse de personnages inutiles. Ça va comme ça:
Cela enregistre même une
main
déclaration standard si vous devez utiliser les arguments de ligne de commande:est deux octets plus court que
J'ai été surpris de découvrir cela, car je ne l'ai pas encore rencontré sur PPCG.
la source
-std=gnu99
et vous n'êtes plus portable. En clair, vous n'écrivez même pas le code "C" en tant que tel, mais "Gnu99-C". 'Ici, nous l'ignorons surtout, mais il est bon de le mentionner si vous postez du code spécifique au compilateur. Parfois , les gens effectivement ne télécharger et exécuter ces programmes de la nôtre. :)-std=c89
pour dire à gcc ou à clang de compiler votre code conformément à cette norme plus ancienne, qui n'autorise implicitement int qu'avec un avertissement.Au lieu de> = et <=, vous pouvez simplement utiliser une division entière (/) lorsque les valeurs comparées sont supérieures à zéro, ce qui enregistre un caractère. Par exemple:
Ce qui est bien sûr toujours rétrécissable, en utilisant par exemple juste> et ^ (un moyen intelligent d’éviter d’écrire && ou || dans certains cas).
L'astuce de la division entière est par exemple utile pour décider si un nombre est inférieur à 100, car cela enregistre un caractère:
Ceci est également utile dans les cas où une priorité plus élevée est nécessaire.
la source
putchar(c>31&c<127?c:46);
Certains compilateurs, tels que GCC, vous permettent d’omettre les
#include
types de base s, param et return pourmain
.Ce qui suit est un programme valide C89 et C99 qui compile (avec des avertissements) avec GCC:
Notez que le
#include
fichier stdio.h est manquant, le type de retour pourmain
manquant et la déclaration de type pouri
manquant.la source
printf()
(ou toute fonction variadique) sans prototype provoque un comportement indéfini . GCC ne compile pas le C standard par défaut. Si vous appelez gcc en mode C89 (gcc -ansi -pedantic
) ou C99 mode (gcc -std=c99 -pedantic
), vous aurez plusieurs plaintes, du moins dans ce dernier cas.L'opérateur conditionnel ternaire
?:
peut souvent être utilisé comme support dans des simplesif
-else
déclarations à des économies considérables.Contrairement à l’équivalent c ++, l’opérateur ne donne pas formellement de valeur , mais certains compilateurs (notamment gcc) vous laisseront vous en tirer, ce qui est un bonus appréciable.
la source
&&
et||
peut également être utilisé:if(x==3)f()
devient avec votre suggestionx==3?f():0
, et peut être encore amélioréx==3&&f()
. Mais soyez prudent avec la priorité des opérateurs - sif()
est remplacé pary=1
, la&&
solution nécessite un ensemble supplémentaire de parenthèses.?:
rapportait une valeur. Puis-je utiliser cela dans le code de production? lolx==3&&f()
peut encore être joué aux^3||f()
http://graphics.stanford.edu/~seander/bithacks.html
Les bits sont gentils.
Mais avec des priorités différentes, et ne changez pas x comme ++ et -. Vous pouvez aussi l'utiliser dans des cas très spécifiques: ~ 9 est plus court que -10.
C'est plus ésotérique, mais j'ai eu l'occasion de l'utiliser. Si vous ne vous souciez pas du court-circuit
Aussi:
la source
(x/y) == (x>=y)
) est vraiment utile.Utilisez lambdas (unportable)
Au lieu de
ou (gcc seulement)
ou (llvm avec le support de blocs)
essayez quelque chose comme
... où la chaîne entre guillemets contient les instructions en langage machine de votre fonction "lambda" (conformes à toutes les exigences de la plate-forme ABI).
Cela fonctionne dans les environnements dans lesquels les constantes de chaîne sont marquées comme étant exécutables. Par défaut, cela est vrai sous Linux et OSX mais pas sous Windows.
Une façon idiote d'apprendre à écrire vos propres fonctions "lambda" consiste à écrire la fonction en C, à la compiler, à l'inspecter avec quelque chose de similaire
objdump -D
et à copier le code hexadécimal correspondant dans une chaîne. Par exemple,... lorsque compilé avec
gcc -Os -c
pour une cible Linux x86_64 génère quelque chose commeGNU CC
goto
:Vous pouvez appeler ces "fonctions lambda" directement, mais si le code que vous appelez ne prend pas de paramètres et ne retourne pas, vous pouvez utiliser
goto
pour enregistrer quelques octets. Donc au lieu deou (si votre environnement n'a pas de glyphes arabes)
Essayer
ou
Dans cet exemple,
eb fe
est le langage machine x86 pour quelque chose commefor(;;);
et est un exemple simple de quelque chose qui ne prend pas de paramètres et ne retournera pas :-)Il s'avère que vous pouvez
goto
coder pour retourner à un parent appelant.L'exemple ci-dessus (pouvant être compilé et exécuté sous Linux avec
gcc -O
) est sensible à la disposition de la pile.EDIT: En fonction de votre chaîne d’outils, vous devrez peut-être utiliser le
-zexecstack
drapeau de compilation.Si ce n'est pas immédiatement évident, cette réponse a été principalement écrite pour les enfants. En lisant ceci, je n’assume aucune responsabilité pour le golf, meilleur ou pire, ni pour les résultats psychologiques défavorables.
la source
Utilisez des curseurs au lieu de pointeurs. Accrochez le
brk()
au début et utilisez-le comme pointeur de base .Puis définissez une #define pour l’accès à la mémoire.
M
devient un postfix*
appliqué aux entiers. (L'ancien a [x] == x [un] tour.)Mais il y a plus! Ensuite, vous pouvez avoir des arguments et des retours de pointeur dans des fonctions plus courtes que les macros (en particulier si vous abrégez "return"):
Pour créer un curseur à partir d'un pointeur, vous soustrayez le pointeur de base, ce qui donne un ptrdiff_t, qui est tronqué en un entier, les pertes sont votre biz.
Cette technique est utilisée dans ma réponse à Ecrire un interprète pour le calcul lambda non typé .
la source
Définissez des paramètres plutôt que des variables.
f(x){int y=x+1;...}
f(x,y){y=x+1;...}
Vous n'avez pas besoin de passer le deuxième paramètre.
En outre, vous pouvez utiliser la priorité des opérateurs pour enregistrer les parenthèses.
Par exemple,
(x+y)*2
peut devenirx+y<<1
.la source
x+y*2
, sauver encore un autre personnage.x+y*2
n'est pas le même, en raison de la priorité des opérateurs.x+y<<1
exemple, en supposant qu'il était évalué ainsix+(y<<1)
, et le suggérai*2
. Je ne savais pas que les opérations de bitshift avaient été évaluées comme par exemple(x+y)<<2
Comme d'habitude
EOF == -1
, utilisez l'opérateur NOT au niveau du bit pour vérifier EOF:while(~(c=getchar()))
ouwhile(c=getchar()+1)
et modifiez la valeur de c à chaque endroitla source
while(1+c=getchar())
marcherait pas ?+
a une priorité plus élevée que l'opérateur d'affectation=
, de sorte1+c=getchar()
équivaut à(1+c)=getchar()
, qui ne compile pas parce que(1+c)
n'est pas une lvalue.L’opérateur ternaire a la
?:
particularité de comporter deux pièces distinctes. Pour cette raison, il fournit une petite échappatoire aux règles de priorité des opérateurs standard. Cela peut être utile pour éviter les parenthèses.Prenons l'exemple suivant:
L’approche habituelle du golf consiste à remplacer le
if
avec&&
, mais à cause de la faible préséance de l’exploitant virgule, vous avez besoin d’une paire de parenthèses supplémentaire:La partie centrale de l'opérateur ternaire n'a pas besoin de parenthèses, cependant:
Des commentaires similaires s'appliquent aux indices de tableau.
la source
b-=a=b
c'est encore plus court. L'?:
astuce est toujours utile,-=
car a également une faible préférence.x>0||(y=3)
,x>0?0:(y=3)
est inutile, maisx<1?y=3:0
fait le travail.x>5?:y=1
Toute partie de votre code qui se répète plusieurs fois est susceptible d'être remplacée par le pré-processeur.
est un cas d'utilisation très courant si votre code implique plus que quelques fonctions. D' autres mots - clés comme oblongues
while
,double
,switch
etcase
sont également des candidats; ainsi que tout ce qui est idomatic dans votre code.Je réserve généralement le caractère majuscule à cette fin.
la source
-DR=return
. Notez que si vous incluez certains caractères, il peut s'avérer nécessaire de placer des guillemets simples ou doubles autour du define-DP='puts("hello")'
.Si votre programme lit ou écrit sur une base à chaque étape, essayez toujours d'utiliser les fonctions lecture et écriture au lieu de getchar () et putchar () .
Exemple ( inverser stdin et placer sur stdout )
Exercice: Utilisez cette technique pour obtenir un bon score ici .
la source
Boucles inverses
Si vous le pouvez, essayez de remplacer
avec
la source
Si vous avez besoin de générer un seul caractère de nouvelle ligne (
\n
), n'utilisez pasputchar(10)
, utilisezputs("")
.la source
Utilisez les valeurs de retour à zéro. Si vous appelez une fonction et que cette fonction renvoie zéro dans des conditions normales, vous pouvez la placer à un emplacement où zéro est attendu. De même, si vous savez que la fonction retournera une valeur nulle, avec l'ajout d'un coup. Après tout, vous ne faites en aucun cas le traitement correct des erreurs dans un code de golf, n'est-ce pas?
Exemples:
la source
Attribuer au lieu de retourner.
Ce n'est pas vraiment C standard, mais fonctionne avec tous les compilateurs et processeurs que je connais:
a le même effet que:
Parce que le premier argument est stocké dans le même registre de la CPU que la valeur de retour.
Remarque: comme indiqué dans un commentaire, il s'agit d'un comportement non défini et non garanti pour chaque opération. Et toute optimisation du compilateur l'ignorera simplement.
X-Macros
Autre fonctionnalité utile: X-Macros peut vous aider lorsque vous avez une liste de variables et que vous devez effectuer certaines opérations qui les impliquent toutes:
https://en.wikipedia.org/wiki/X_Macro
la source
-O0
choisit toujours d'évaluer les expressions dans le registre de valeur de retour. J'ai au moins regardé x86, ARM et MIPS (sur gcc.godbolt.org ), et gcc semble faire de son mieux pour le faire-O0
. Mais rappelez - vous si vous prenez avantage de cela, la langue que vous la programmation en est -gcc -O0
, pas C , et vous devriez étiqueter votre réponse en conséquence, non pas comme C . Il échoue à tous les niveaux d'optimisation autres que le-O0
mode débogage et ne fonctionne pas avec Clang IIRC.Utilisez
*a
au lieu dea[0]
pour accéder au premier élément d'un tableau.Les opérateurs relationnels (
!=
,>
, etc.) donnent0
ou1
. Utilisez ceci avec des opérateurs arithmétiques pour donner différents décalages selon que la condition est vraie ou fausse:a[1+2*(i<3)]
accéderaita[1]
sii >= 3
eta[3]
autrement.la source
a[i<3?3:1]
est deux caractères plus court quea[1+2*(i<3)]
.Vous pouvez consulter les archives de l'IOCCC (concours international de code C obfusqué).
Une astuce notable consiste à # définir des macros dont le développement comporte des accolades / parenthèses non équilibrées, comme
la source
#define P;printf(
.for(int i=0;i<n;i++){a(i);b(i);}
peut être raccourci de plusieurs manières:for(int i=0;i<n;){a(i);b(i++);}
-1 pour déplacer++
le dernieri
dans la bouclefor(int i=0;i<n;b(i++))a(i);
-3 de plus pour déplacer toutes les instructions sauf une dans le haut et hors de la boucle principale, en supprimant les accoladesla source
Allez fonctionnel!
Si vous pouvez réduire votre problème à des fonctions simples avec la même signature et définies comme des expressions uniques, vous pouvez alors faire mieux que de
#define r return
factoriser la quasi-totalité du passe-partout pour définir une fonction.Le résultat du programme est sa valeur d'état renvoyée au système d'exploitation ou au shell ou IDE de contrôle.
Utiliser
__VA_ARGS__
vous permet d'utiliser l'opérateur de virgule pour introduire des points de séquence dans ces expressions de fonction . Si cela n'est pas nécessaire, la macro peut être plus courte.la source
utiliser
scanf("%*d ");
pour lire l'entrée factice. (si cette entrée n'a pas de sens dans le programme suivant), elle est plus courte que celle pourscanf("%d",&t);
laquelle vous devez également déclarer la variable t.stocker des caractères dans un tableau int est bien meilleur qu'un tableau de caractères. exemple.
s[],t;main(c){for(scanf("%*d ");~(c=getchar());s[t++]=c)putchar(s[t]);}
la source
%*d
non seulement dans le golf, mais aussi dans les situations où l'on voudrait, par exemple, sauter une nouvelle ligne dansscanf("%[^\n]%*c",str);
:)Imprimer un caractère puis un retour chariot au lieu de:
ou
tout simplement, déclarez c comme un int et:
la source
puts(&c)
vraiment? Cela ne serait pas nécessairement terminé par un zéro.char *
, on voit une chaîne singleton: le caractère c , suivi d'un octet nul.L'utilisation
asprintf()
vous permet d'économiser l'allocation explicite et la mesure de la longueur d'une chaîne akachar*
! Ce n'est peut-être pas très utile pour le golf de code, mais facilite le travail quotidien avec un tableau de caractères. Il y a encore d'autres bons conseils au 21ème siècle .Exemple d'utilisation:
la source
import
si tu doisComme indiqué dans la toute première réponse , certains compilateurs (notamment GCC et clang) vous permettent d'omettre
#include
s pour omettre les fonctions de bibliothèque standard.Même si vous ne pouvez pas simplement supprimer le fichier
#include
, il existe peut-être d' autres moyens de l'éviter , mais ce n'est pas toujours pratique ni particulièrement risqué.Dans les cas restants, vous pouvez utiliser
#import<header file>
au lieu de#include<header file>
sauvegarder un octet. Ceci est une extension GNU et il est considéré comme obsolète, mais cela fonctionne au moins dans gcc 4.8, gcc 5.1 et clang 3.7.la source
Essayer
cpow()
au lieu decos()
Au lieu de
essayez quelque chose comme
Ceci utilise la formule d'Euler , une petite analyse complexe et l'observation qui attribue un complexe à un double donne la partie réelle (attention aux appels de fonctions variadiques et autres subtilités).
Ce type d’astuce peut être utilisé pour réduire
dans
la source
Voici quelques conseils que j'ai utilisés à mon avantage. Je les ai volés sans vergogne aux autres, soyez donc reconnaissant envers quiconque sauf moi:
Combiner une affectation avec des appels de fonction
Au lieu de cela:
Faire ceci:
Initialiser plusieurs variables ensemble (si possible)
Au lieu de cela:
Faire ceci:
Réduire les valeurs nulles / non nulles
C’est un bon tour que j’ai appris de quelqu'un d’ici (je ne me souviens pas de qui, pardon). Lorsque vous avez une valeur entière et que vous devez la réduire à 1 ou à 0, vous pouvez l'utiliser
!!
pour le faire facilement. C'est parfois avantageux pour d'autres alternatives comme?:
.Prenez cette situation:
Vous pourriez plutôt faire ceci:
Un autre exemple:
Pourrait être réécrit comme:
la source
R*-~!!mxxxx
Connaître les égalités logiques de base peut permettre de sauver quelques octets. Par exemple, au lieu d'
if (!(a&&b)){}
essayer d'utiliser la loi de DeMorganif (!a||!b){}
. La même chose s'applique aux fonctions au niveau du bit: au lieu de~(a|b)
faire~a&~b
.la source