回答:
ビットごとのXORを使用して、整数間の不等式をチェックします。
if(a^b)
代わりにif(a!=b)
1文字を保存します。
a-b
同じ効果が得られます。
a*b
に、代わりに使用することができますa&&b
(優先順位が異なる、悪い場合もそうでない場合もあります)。/ = -bがわかっている場合(例:符号なし)、a||b
==a+b
?:
(ifの代わりに)エルビス演算子と組み合わせることをお勧めします。異なる場合に何かを実行するための例: a^b?_diff_:;
?:
にはちょうど同等であるオペレータa ? a : b
Abuse main
の引数リストを使用して、1つ以上の整数変数を宣言します。
main(a){for(;++a<28;)putchar(95+a);}
(プログラミング言語のアルファベットへの回答)
この解決策は、プログラムが引数なしで呼び出される場合、a
(aka argc
)として始まるという事実も悪用し1
ます。
グローバル変数を使用して、物事をゼロに初期化します。
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");}
(アナグラムコードゴルフへの答え!)
カンマ演算子を使用して、ブレースを回避しながら、1つのブロックで複数の式を実行できます。
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");
}
出力: 1 2
break
。
break
は声明であり、この答えは式に関するものです。
5つの引数がすべてint
sである関数を宣言している場合、人生は良いものです。あなたは簡単に書くことができます
f(a,b,c,d,e){
しかし仮定するd
ニーズがあることをchar
、またはさえint*
。その後、あなたはめちゃくちゃです!1つのパラメーターの前に型が付いている場合、それらはすべて次のようにする必要があります。
f(int a,int b,int c,int*d,int e){
ちょっと待って!役に立たないキャラクターのこの悲惨な爆発を回避する方法があります。こんなふうになります:
f(a,b,c,d,e) int *d; {
main
コマンドライン引数を使用する必要がある場合、これは標準宣言を節約します:
main(c,v)char**v;{
より2バイト短い
main(int c,char**v){
PPCGでこれまで出会ったことがないので、これを発見して驚いた。
-std=gnu99
あり、今は移植性がありません。clc-speakでは、「C」コード自体を書いているのではなく、「Gnu99-C」を書いています。「ここではラウンドはほとんど無視していますが、コンパイラ固有のコードを投稿する場合は言及するのが良いでしょう。時には人々は実際にこれらのプログラムをダウンロードして実行します。:)
-std=c89
して、gccまたはclangに古い標準に従ってコードをコンパイルするように指示できます。これにより、警告のみで暗黙的なintが許可されます。
> =および<=の代わりに、比較される値がゼロよりも大きい場合に整数除算(/)を使用するだけで、1文字節約できます。例えば:
putchar(c/32&&126/c?c:46); //Prints the character, but if it is unprintable print "."
もちろん、これは、たとえば>と^だけを使用して(場合によっては&&や||と書くのを避ける賢い方法です)、まだ縮小可能です。
putchar(c>31^c>126?c:46);
整数除算のトリックは、たとえば、数字が100未満かどうかを判断するのに役立ちます。これにより、文字が節約されます。
a<100 vs 99/a
これは、より高い優先順位が必要な場合にも適しています。
putchar(c>31&c<127?c:46);
GCCなどの特定のコンパイラでは、の基本的な#include
s、param、および戻り値の型を省略できますmain
。
以下は、GCCでコンパイル(警告付き)する有効なC89およびC99プログラムです。
main(i) { printf("%d", i); }
#include
for stdio.hが欠落していること、戻り値の型main
が欠落していること、および型宣言が欠落していることに注意してくださいi
。
printf()
プロトタイプなしで呼び出す(または任意の可変引数関数)と、未定義の動作が発生します。GCCはデフォルトでは標準Cをコンパイルしません。C89モード(gcc -ansi -pedantic
)またはC99モード(gcc -std=c99 -pedantic
)でgccを呼び出すと、少なくとも後者の場合、かなりの苦情が寄せられます。
三項条件演算子は?:
、多くの場合、単純なためでスタンドとして使用することができますif
- else
かなりの節約に文。
C ++の同等物とは異なり、演算子は正式には左辺値を生成しませんが、一部のコンパイラ(特にgcc)はそれを回避できます。これは素晴らしいボーナスです。
&&
と||
にも使用することができます:if(x==3)f()
あなたの提案となりx==3?f():0
、さらにに向上することができますx==3&&f()
。ただし、演算子の優先順位に注意してください- f()
をに置き換えた場合y=1
、&&
ソリューションには追加の括弧が必要です。
?:
が左辺値を生成することを理解していませんでした。本番コードで使用できますか?笑
x==3&&f()
さらにゴルフすることができますx^3||f()
http://graphics.stanford.edu/~seander/bithacks.html
ビットがいいです。
~-x = x - 1
-~x = x + 1
しかし、優先順位は異なりますが、xを++や-のように変更しないでください。また、これは実際に特定のケースで使用できます:〜9は-10より短いです。
if(!(x&y)) x | y == x ^ y == x + y
if(!(~x&y)) x ^ y == x - y
それはもっと難解ですが、私はそれを使用する機会がありました。短絡を気にしない場合
x*y == x && y
if(x!=-y) x+y == x || y
また:
if(x>0 && y>0) x/y == x>=y
(x/y) == (x>=y)
)は本当に便利です。
の代わりに
f(int*a,int*b){return*a>*b?1:-1;}
...
qsort(a,b,4,f);
または(gccのみ)
qsort(a,b,4,({int L(int*a,int*b){a=*a>*b?1:-1;}L;}));
または(ブロックをサポートするllvm)
qsort_b(a,b,4,^(const void*a,const void*b){return*(int*)a>*(int*)b?1:-1;});
のようなものを試してください
qsort(a,b,4,"\x8b\7+\6\xc3");
...ここで、引用符で囲まれた文字列には、「ラムダ」関数のマシン言語命令が含まれています(すべてのプラットフォームABI要件に準拠)。
これは、文字列定数が実行可能とマークされている環境で機能します。デフォルトでは、これはLinuxおよびOSXに当てはまりますが、Windowsには当てはまりません。
独自の「ラムダ」関数を書くことを学ぶ愚かな方法の1つは、Cで関数を記述し、それをコンパイルし、何かで検査しobjdump -D
、対応する16進コードを文字列にコピーすることです。例えば、
int f(int*a, int*b){return *a-*b;}
... gcc -Os -c
Linux x86_64ターゲット用にコンパイルすると、次のようなものが生成されます
0: 8b 07 mov (%rdi),%eax
2: 2b 06 sub (%rsi),%eax
4: c3 retq
goto
:これらの「ラムダ関数」を直接呼び出すことはできますが、呼び出しているコードがパラメーターを受け取らず、返されない場合はgoto
、数バイトを節約するために使用できます。の代わりに
((int(*)())L"ﻫ")();
または(環境にアラビア語のグリフがない場合)
((int(*)())L"\xfeeb")();
試して
goto*&L"ﻫ";
または
goto*&L"\xfeeb";
この例でeb fe
は、x86マシン言語のようなものfor(;;);
であり、パラメーターを使用せず、返されないものの簡単な例です:-)
goto
呼び出し元の親に戻るコードを作成できることがわかりました。
#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));
}
上記の例(Linuxでを使用してコンパイルおよび実行する場合がありますgcc -O
)は、スタックレイアウトの影響を受けます。
編集:ツールチェーンによっては、-zexecstack
コンパイルフラグを使用する必要がある場合があります。
すぐに明らかにならない場合、この答えは主に笑いのために書かれました。これを読んだことによるゴルフの良し悪しや悪い心理的結果について、私は一切責任を負いません。
ポインターの代わりにカーソルを使用します。brk()
最初にスナッグし、それをベースポインターとして使用します。
char*m=brk();
次に、メモリアクセス用に#defineを作成します。
#define M [m]
M
*
整数に適用される接尾辞になります。(古いa [x] == x [a]トリック。)
しかし、もっとあります!次に、ポインタ引数を使用して、マクロよりも短い関数で返すことができます(特に「return」を省略した場合)。
f(x){return x M;} //implicit ints, but they work like pointers
#define f(x) (x M)
ポインターからカーソルを作成するには、ベースポインターを減算し、intに切り捨てられるptrdiff_tを生成します。損失はyer bizです。
char *p = sbrk(sizeof(whatever)) - m;
strcpy(m+p, "hello world");
この手法は、型なしラムダ計算のインタプリタを作成するという私の答えで使用されます。
変数の代わりにパラメーターを定義します。
f(x){int y=x+1;...}
f(x,y){y=x+1;...}
実際に2番目のパラメーターを渡す必要はありません。
また、演算子の優先順位を使用して括弧を保存できます。
たとえば、に(x+y)*2
なりx+y<<1
ます。
x+y*2
、さらに別の文字を保存します。
x+y*2
演算子の優先順位のため、同じではありません。
x+y<<1
として評価されていると仮定して、例に固執しx+(y<<1)
、*2
代わりに提案しました。ビットシフト操作が次のように評価されることを知りませんでした(x+y)<<2
通常EOF == -1
は、ビット単位のNOT演算子を使用してEOFを確認します:while(~(c=getchar()))
またはwhile(c=getchar()+1)
、すべての場所でcの値を変更します
while(1+c=getchar())
動作しませんか?
+
代入演算子よりも優先順位が高い=
ので、1+c=getchar()
と等価である(1+c)=getchar()
ので、コンパイルしない、(1+c)
左辺値ではありません。
三項演算子?:
は、2つの部分に分かれているという点で異常です。このため、標準の演算子優先順位ルールに少し抜け道があります。これは、括弧を避けるのに役立ちます。
次の例をご覧ください。
if (t()) a = b, b = 0; /* 15 chars */
通常のゴルフのアプローチはif
with を置き換える&&
ことですが、カンマ演算子の優先順位が低いため、追加の括弧が必要です。
t() && (a = b, b = 0); /* still 15 chars */
ただし、三項演算子の中央セクションには括弧は必要ありません。
t() ? a = b, b = 0 : 0; /* 14 chars */
同様のコメントが配列添え字に適用されます。
b-=a=b
は、さらに短くなっています。?:
トリックは、まだ役に立つ-=
も低い優先度を持っているので。
x>0||(y=3)
、x>0?0:(y=3)
役に立たないですが、x<1?y=3:0
仕事をしていません。
x>5?:y=1
プログラムが各ステップごとに読み取りまたは書き込みを行っている場合は、常にgetchar()およびputchar()の代わりに読み取りおよび書き込み機能を使用してください。
main(_){write(read(0,&_,1)&&main());}
単一の改行文字(\n
)を出力する必要がある場合はputchar(10)
、使用しないでくださいputs("")
。
これは実際には標準のCではありませんが、私が知っているすべてのコンパイラとCPUで動作します。
int sqr(int a){return a*a;}
次と同じ効果があります。
int sqr(int a){a*=a;}
最初の引数は戻り値と同じCPUレジスタに格納されるためです。
注:1つのコメントで述べたように、これは未定義の動作であり、すべての操作で機能することは保証されていません。そして、コンパイラの最適化はそれをスキップします。
別の便利な機能:変数のリストがあり、それらすべてを含む操作を行う必要がある場合、X-Macrosが役立ちます。
-O0
常に、戻り値レジスタ内の式を評価することを選択します。私は少なくとも(gcc.godbolt.orgで)x86、ARM、およびMIPSを見てきましたが、gccはでそれを行う方法から外れているようです-O0
。あなたは、これを利用場合でも、覚えて、あなたがでプログラミングしている言語gcc -O0
、ないCのないCとして、あなたはそれに応じてあなたの答えにラベルを付ける必要があります。-O0
デバッグモード以外の最適化レベルでは失敗し、clang IIRCでは機能しません。
同じシグニチャを持ち、単一の式として定義された単純な関数に問題を減らすことができれば#define r return
、関数を定義するためのほぼすべての定型文よりも優れた結果を得ることができます。
#define D(f,...)f(x){return __VA_ARGS__;}
D(f,x+2)
D(g,4*x-4)
D(main,g(4))
プログラムの結果は、OSまたは制御シェルまたはIDEに返されるステータス値です。
を使用__VA_ARGS__
すると、コンマ演算子を使用してこれらのfunction-expressionにシーケンスポイントを導入できます。これが不要な場合は、マクロを短くすることができます。
#define D(f,b)f(x){return b;}
scanf("%*d ");
ダミー入力の読み取りに使用します。(入力がさらなるプログラムで無意味である場合)scanf("%d",&t);
、変数tを宣言する必要がある場所よりも短くなります。
文字をint配列に格納することは、文字配列よりもはるかに優れています。例。
s[],t;main(c){for(scanf("%*d ");~(c=getchar());s[t++]=c)putchar(s[t]);}
%*d
、それはまた、1つは、例えば、中に改行をスキップしたいと思うような状況で有用ですので、ゴルフだけでなくscanf("%[^\n]%*c",str);
:)
次の代わりに、文字を印刷してから復帰します。
printf("%c\n",c);
または
putchar(c);putchar('\n'); // or its ascii value, whatever!
単純に、cをintとして宣言し、次のようにします。
puts(&c);
puts(&c)
本当に仕事?それは必ずしもヌルで終わるわけではありません。
char *
、シングルトン文字列、つまり文字cの後にヌルバイトが続きます。
を使用asprintf()
すると、明示的に割り当てられ、文字列の長さを測定することも節約されますchar*
!これは、おそらくコードゴルフにはあまり便利ではありませんが、char配列を使用して日常の作業を容易にします。21世紀Cにはさらに良いアドバイスがあります。
使用例:
#define _GNU_SOURCE
#include <stdio.h>
int main(int argc, char** argv) {
char* foo;
asprintf(&foo, "%s", argv[1]);
printf("%s",foo);
}
import
あなたがする必要がある場合最初の回答で述べたように、一部のコンパイラ(特にGCCとclang)では、#include
標準ライブラリ関数のs を省略しても問題ありません。
を単に削除できない場合でも、それを回避する他の方法#include
があるかもしれませんが、それは常に実用的または特にゴルフに適しているわけではありません。
残りのケースでは、#import<header file>
代わりに#include<header file>
を使用してバイトを保存できます。これはGNU拡張機能であり、非推奨と見なされますが、少なくともgcc 4.8、gcc 5.1、およびclang 3.7で機能します。
ここに、私が使ったいくつかのヒントを示します。私は恥知らずに他人からそれらを盗んだので、私以外の誰にでも信用:
割り当てと関数呼び出しを組み合わせる
これの代わりに:
r = /* Some random expression */
printf("%d", r);
これを行う:
printf("%d", r = /* Some random expression */);
複数の変数を一緒に初期化する(可能な場合)
これの代わりに:
for(i=0,j=0;...;...){ /* ... */ }
これを行う:
for(i=j=0;...;...){ /* ... */ }
ゼロ/非ゼロ値を折りたたむ
これは私がここにいる誰かから拾ったすてきなトリックです(覚えていないで、申し訳ありません)。整数値があり、それを1または0に折りたたむ必要がある場合!!
、簡単に使用できます。これは、のような他の選択肢のために有利であることがあります?:
。
この状況を考えてみましょう。
n=2*n+isupper(s[j])?1:0; /* 24 */
代わりにこれを行うことができます:
n=n*2+!!isupper(s[j]); /* 22 */
もう一つの例:
r=R+(memcmp(b+6,"---",3)?R:0); /* 30 */
次のように書き換えることができます。
r=R+R*!!memcmp(b+6,"---",3)); /* 29 */
R*-~!!mxxxx