¿Qué consejos generales tienes para jugar al golf en C? Estoy buscando ideas que se puedan aplicar a los problemas de golf de código en general que sean al menos algo específicos para C (por ejemplo, "eliminar comentarios" no es una respuesta). Por favor, publique un consejo por respuesta. Además, incluya si su sugerencia se aplica a C89 y / o C99 y si solo funciona en ciertos compiladores.
138
Respuestas:
Use XOR bit a bit para verificar la desigualdad entre enteros:
if(a^b)
en lugar deif(a!=b)
guardar 1 personaje.fuente
a-b
te da el mismo efecto.a*b
lugar dea&&b
(tiene una precedencia diferente, puede o no ser malo). Si conoce a / = -b (por ejemplo, no están firmados) entoncesa||b
==a+b
?:
(en lugar de si): por ejemplo, simplemente haga algo si es diferente:a^b?_diff_:;
?:
operador que es sólo equivalente aa ? a : b
main
Lista de argumentos de abuso para declarar una o más variables enteras:(respuesta al alfabeto en lenguajes de programación )
Esta solución también abusa del hecho de que
a
(akaargc
) comienza como1
, siempre que se llame al programa sin argumentos.Use variables globales para inicializar cosas a cero:
(¡respuesta a Anagram Code Golf! )
fuente
El operador de coma se puede usar para ejecutar múltiples expresiones en un solo bloque evitando llaves:
Salidas:
1 2
fuente
break
.break
es una declaración, y esta respuesta está hablando de expresiones.Evite declaraciones catastróficas de tipo argumento-función
Si está declarando una función donde los cinco argumentos son
int
s, entonces la vida es buena. simplemente puedes escribirPero supongamos que
d
necesita ser unchar
, o incluso unint*
. ¡Entonces estás jodido! Si un parámetro está precedido por un tipo, todos deben ser:¡Pero espera! Hay una forma de evitar esta desastrosa explosión de personajes inútiles. Dice así:
Esto incluso ahorra en una
main
declaración estándar si necesita utilizar los argumentos de la línea de comandos:es dos bytes más corto que
Me sorprendió descubrir esto, ya que hasta ahora no lo he encontrado en PPCG.
fuente
-std=gnu99
y ahora no es portátil. En clc-speak, ni siquiera está escribiendo el código "C" per se, sino "Gnu99-C". 'Por aquí ignoramos eso en su mayoría, pero es bueno mencionarlo si publicas código que es específico del compilador. A veces la gente realmente no descargar y ejecutar estos programas de la nuestra. :)-std=c89
para decirle a gcc o clang que compile su código de acuerdo con ese estándar anterior, que permite int implícito con solo una advertencia.En lugar de> = y <= simplemente puede usar la división entera (/) cuando los valores comparados están por encima de cero, lo que ahorra un carácter. Por ejemplo:
Lo cual, por supuesto, todavía es encogible, usando por ejemplo solo> y ^ (una forma inteligente de evitar escribir && o || en algunos casos).
El truco de la división de enteros es, por ejemplo, útil para decidir si un número es menor que 100, ya que esto guarda un carácter:
Esto también es bueno en los casos en que se necesita una mayor prioridad.
fuente
putchar(c>31&c<127?c:46);
Ciertos compiladores, como GCC, le permiten omitir básicas
#include
s, parámetro y tipos de devolución demain
.El siguiente es un programa válido C89 y C99 que compila (con advertencias) con GCC:
Observe que
#include
falta el for stdio.h, falta el tipo de retorno para ymain
falta la declaración de tipo parai
.fuente
printf()
(o cualquier función variada) sin un prototipo provoca un comportamiento indefinido . GCC no compila el estándar C por defecto. Si invoca gcc en modo C89 (gcc -ansi -pedantic
) o modo C99 (gcc -std=c99 -pedantic
), recibirá bastantes quejas, al menos en el último caso.El operador condicional ternario
?:
menudo se puede utilizar como soporte en por simplesif
-else
declaraciones en un ahorro considerable.A diferencia del equivalente de c ++, el operador no produce formalmente un valor l , pero algunos compiladores (especialmente gcc) le permitirán salirse con la suya, lo cual es una buena ventaja.
fuente
&&
y||
también se puede usar: seif(x==3)f()
convierte con su sugerenciax==3?f():0
, y se puede mejorar aún másx==3&&f()
. Pero tenga cuidado con la precedencia del operador: sif()
se reemplaza cony=1
, entonces la&&
solución requiere un conjunto adicional de paréntesis.?:
produce un valor l. ¿Puedo usar eso en el código de producción? lolx==3&&f()
se puede seguir jugando alx^3||f()
http://graphics.stanford.edu/~seander/bithacks.html
Los bits son buenos.
Pero con diferentes precedentes, y no cambies x como ++ y -. También puede usar esto en casos realmente específicos: ~ 9 es más corto que -10.
Eso es más esotérico, pero he tenido la ocasión de usarlo. Si no te importa el cortocircuito
También:
fuente
(x/y) == (x>=y)
) es realmente útil.Use lambdas (no portable)
En lugar de
o (solo gcc)
o (llvm con soporte de bloques)
prueba algo como
... donde la cadena entre comillas contiene las instrucciones del lenguaje máquina de su función "lambda" (conforme a todos los requisitos ABI de la plataforma).
Esto funciona en entornos en los que las constantes de cadena se marcan como ejecutables. Por defecto, esto es cierto en Linux y OSX pero no en Windows.
Una forma tonta de aprender a escribir sus propias funciones "lambda" es escribir la función en C, compilarla, inspeccionarla con algo parecido
objdump -D
y copiar el código hexadecimal correspondiente en una cadena. Por ejemplo,... cuando se compila
gcc -Os -c
para un objetivo Linux x86_64 genera algo comoGNU CC
goto
:Puede llamar a estas "funciones lambda" directamente, pero si el código al que llama no toma parámetros y no va a regresar, puede usar
goto
para guardar algunos bytes. Entonces en lugar deo (si su entorno no tiene glifos árabes)
Tratar
o
En este ejemplo,
eb fe
es lenguaje de máquina x86 para algo asífor(;;);
y es un ejemplo simple de algo que no toma parámetros y no va a volver :-)Resulta que puede
goto
codificar que vuelve a un padre que llama.El ejemplo anterior (podría compilarse y ejecutarse en Linux con
gcc -O
) es sensible al diseño de la pila.EDITAR: Dependiendo de su cadena de herramientas, es posible que deba usar el
-zexecstack
indicador de compilación.Si no es evidente de inmediato, esta respuesta se escribió principalmente para los lols. No me hago responsable de jugar golf mejor o peor o de resultados psicológicos adversos al leer esto.
fuente
Use cursores en lugar de punteros. Enganche el
brk()
al principio y úselo como puntero base .Luego haga un #define para acceder a la memoria.
M
se convierte en un postfix*
aplicado a enteros. (El viejo truco de a [x] == x [a]).¡Pero hay más! Entonces puede tener argumentos y retornos de puntero en funciones que son más cortas que las macros (especialmente si abrevia 'return'):
Para hacer un cursor desde un puntero, resta el puntero base, produciendo un ptrdiff_t, que se trunca en int, las pérdidas son su negocio.
Esta técnica se utiliza en mi respuesta para Escribir un intérprete para el cálculo lambda sin tipo .
fuente
Definir parámetros en lugar de variables.
f(x){int y=x+1;...}
f(x,y){y=x+1;...}
No necesita pasar el segundo parámetro.
Además, puede utilizar la precedencia del operador para guardar paréntesis.
Por ejemplo,
(x+y)*2
puede convertirsex+y<<1
.fuente
x+y*2
, ahorrando otro personaje más.x+y*2
no es lo mismo, debido a la precedencia del operador.x+y<<1
ejemplo, asumiendo que estaba siendo evaluado comox+(y<<1)
, y sugerí el*2
lugar. No sabía que las operaciones de desplazamiento de bits se evaluaran como, por ejemplo(x+y)<<2
Dado que por lo general
EOF == -1
, utilizar el bit a bit NO operador para comprobar si hay EOF:while(~(c=getchar()))
owhile(c=getchar()+1)
y modificar el valor de c en todos los lugaresfuente
while(1+c=getchar())
funcionaría?+
tiene mayor precedencia que el operador de asignación=
, por lo que1+c=getchar()
es equivalente a(1+c)=getchar()
, que no se compila porque(1+c)
no es un valor l.El operador ternario
?:
es inusual porque tiene dos piezas separadas. Debido a esto, proporciona un poco de escapatoria a las reglas de precedencia de operadores estándar. Esto puede ser útil para evitar paréntesis.Tome el siguiente ejemplo:
El enfoque de golf habitual es reemplazar el
if
con&&
, pero debido a la baja precedencia del operador de coma, necesita un par adicional de paréntesis:Sin embargo, la sección central del operador ternario no necesita paréntesis:
Comentarios similares se aplican a los subíndices de matriz.
fuente
b-=a=b
es aún más corto. El?:
truco sigue siendo útil,-=
porque también tiene poca preferencia.x>0||(y=3)
,x>0?0:(y=3)
no sirve para nada, perox<1?y=3:0
hace el trabajo.x>5?:y=1
Cualquier parte de su código que se repita varias veces es un candidato para el reemplazo con el preprocesador.
es un caso de uso muy común si su código involucra más de un par de funciones. Otras palabras clave bastante largas como
while
,double
,switch
, ycase
son también candidatos; así como cualquier cosa que sea idomática en su código.Generalmente reservo caracteres en mayúscula para este propósito.
fuente
-DR=return
. Tenga en cuenta que si incluye ciertos caracteres, puede ser necesario tener comillas simples o dobles alrededor de la definición-DP='puts("hello")'
.Si su programa lee o escribe en cada paso, intente siempre usar la función de lectura y escritura en lugar de getchar () y putchar () .
Ejemplo ( revertir stdin y colocar en stdout )
Ejercicio: use esta técnica para obtener una buena puntuación aquí .
fuente
Bucles inversos
Si puedes, intenta reemplazar
con
fuente
Si alguna vez necesita generar un solo carácter de nueva línea (
\n
), no useputchar(10)
, useputs("")
.fuente
Hacer uso de valores de retorno a cero cosas. Si llama a alguna función, y esa función devuelve cero en condiciones normales, puede colocarla en una ubicación donde se espera cero. Del mismo modo, si sabe que la función devolverá un valor distinto de cero, con la adición de una explosión. Después de todo, en cualquier caso, no manejas los errores correctamente en un código de golf, ¿verdad?
Ejemplos:
fuente
Asignar en lugar de devolver.
Esto no es realmente C estándar, pero funciona con todos los compiladores y CPU que conozco:
tiene el mismo efecto que:
Porque el primer argumento se almacena en el mismo registro de CPU que el valor de retorno.
Nota: Como se señaló en un comentario, este es un comportamiento indefinido y no se garantiza que funcione para todas las operaciones. Y cualquier optimización del compilador lo omitirá.
Macros X
Otra característica útil: X-Macros puede ayudarlo cuando tiene una lista de variables y necesita realizar alguna operación que involucre a todas ellas:
https://en.wikipedia.org/wiki/X_Macro
fuente
-O0
siempre elige evaluar expresiones en el registro de valor de retorno. He visto x86, ARM y MIPS al menos (en gcc.godbolt.org ), y parece que gcc hace todo lo posible para hacerlo-O0
. Pero recuerde que si usted toma ventaja de esto, el lenguaje de programación que está en decirgcc -O0
, no C , y se debe etiquetar su respuesta en consecuencia, no como C . Falla en cualquier nivel de optimización que no sea el-O0
modo de depuración, y no funciona con clang IIRC.Use en
*a
lugar dea[0]
para acceder al primer elemento de una matriz.Los operadores relacionales (
!=
,>
, etc.) dan0
o1
. Use esto con operadores aritméticos para dar diferentes compensaciones dependiendo de si la condición es verdadera o falsa:a[1+2*(i<3)]
accederíaa[1]
sii >= 3
y dea[3]
otra manera.fuente
a[i<3?3:1]
son dos caracteres más cortos quea[1+2*(i<3)]
.Puede consultar los archivos de IOCCC (concurso internacional de códigos C ofuscados).
Un truco notable es #definir macros cuya expansión tiene paréntesis / llaves desequilibradas, como
fuente
#define P;printf(
.for(int i=0;i<n;i++){a(i);b(i);}
se puede acortar de varias maneras:for(int i=0;i<n;){a(i);b(i++);}
-1 para mover++
al últimoi
en el buclefor(int i=0;i<n;b(i++))a(i);
-3 más para mover todas las declaraciones menos una a la parte superior y fuera del bucle principal, eliminando las llavesfuente
¡Vaya funcional!
Si puede reducir su problema a funciones simples con la misma firma y definidas como expresiones individuales, entonces puede hacerlo mejor
#define r return
y factorizar casi todo el estándar para definir una función.El resultado del programa es su valor de estado devuelto al sistema operativo o al shell de control o IDE.
El uso le
__VA_ARGS__
permite utilizar el operador de coma para introducir puntos de secuencia en estas expresiones de función . Si esto no es necesario, la macro puede ser más corta.fuente
se usa
scanf("%*d ");
para leer la entrada ficticia. (en caso de que la entrada no tenga sentido en otro programa) es más corta quescanf("%d",&t);
donde también necesita declarar la variable t.almacenar caracteres en la matriz int es mucho mejor que la matriz de caracteres. ejemplo.
s[],t;main(c){for(scanf("%*d ");~(c=getchar());s[t++]=c)putchar(s[t]);}
fuente
%*d
no sólo en Golf, ya que también es útil en situaciones en las que uno podría, por ejemplo, quiera saltarse una nueva línea enscanf("%[^\n]%*c",str);
:)Imprima un carácter y luego retorno de carro, en lugar de:
o
simplemente, declare c como int y:
fuente
puts(&c)
Realmente funciona? Eso no sería necesariamente nulo terminado.char *
, vemos una cadena singleton: el carácter c , seguido de un byte nulo.¡El uso le
asprintf()
ahorra la asignación explícita y también mide la longitud de una cadena akachar*
! Esto quizás no sea demasiado útil para el golf de código, pero facilita el trabajo diario con una matriz de caracteres. Hay algunos más buenos consejos en el siglo XXI .Ejemplo de uso:
fuente
import
si usted tiene queComo se señaló en la primera respuesta , algunos compiladores (en particular, GCC y clang) le permiten omitir
#include
s para las funciones estándar de la biblioteca.Incluso si no puede simplemente eliminarlo
#include
, puede haber otras formas de evitarlo , pero eso no siempre es práctico o particularmente deportivo.En los casos restantes, puede usar en
#import<header file>
lugar de#include<header file>
guardar un byte. Esta es una extensión de GNU y se considera obsoleta, pero funciona al menos en gcc 4.8, gcc 5.1 y clang 3.7.fuente
Probar en
cpow()
lugar decos()
En lugar de
prueba algo como
Utiliza la fórmula de Euler , un pequeño análisis complejo y la observación de que asignar un complejo a un doble produce la parte real (cuidado con las llamadas a funciones variables y otras sutilezas).
Este tipo de truco se puede usar para reducir
dentro
fuente
Aquí hay algunos consejos que he usado para mi ventaja. Los robé descaradamente a otros, así que dale crédito a todos menos a mí:
Combinar asignación con llamadas a funciones
En lugar de esto:
Hacer esto:
Inicializar múltiples variables juntas (cuando sea posible)
En lugar de esto:
Hacer esto:
Contraer valores cero / distintos de cero
Este es un buen truco que aprendí de alguien aquí (no recuerdo quién, lo siento). Cuando tiene un valor entero y necesita contraerlo a 1 o 0, puede
!!
hacerlo fácilmente. Esto a veces es ventajoso para otras alternativas como?:
.Toma esta situación:
En su lugar, podría hacer esto:
Otro ejemplo:
Podría reescribirse como:
fuente
R*-~!!mxxxx
Conocer las igualdades lógicas básicas podría salvar un par de bytes. Por ejemplo, en lugar de
if (!(a&&b)){}
intentar usar la ley de DeMorganif (!a||!b){}
. Lo mismo se aplica a las funciones bit a bit: en lugar de~(a|b)
do~a&~b
.fuente