しょうとこうでぃんぐ
皆さん久しぶり もうこいつはブログ更新しないんじゃないかと思っている方もいるでしょう。
冴えてるね! 私もそう思っていました。だがしかし 時が進むと私の目の前にでてくるあらゆる話題。
これを赤歴史に記さんと思いますた。いろいろかくよーん。前回の画像をソースコードにする奴はなんやかんやで面白かったから
今回はショートコーディングについて。
ショートコーディングとは?
プログラムを短く書こうぜ!
美しさとか可読性とかどうでもいいから短くしようぜ!
ショートコーディングのルール!
ライブラリを作ればどんなコードも短くなるさ!
そんなのずるいぜ! 短さの美学に反する!
コンパイラしだいで動いたり動かなかったりだけど、
とりあえずAOJとかPKUがおkしてくれればいいんじゃまいか。
例
手始めにAOJ0000をショートコーディングしてみる。
とりあえず普通に組む。
はい ちゃんとAcceptです
さて短くするのですが
ということで
えー前の3点のほかに宣言がmainの引数の中に入ってますね。
さきほど宣言のintはいらないと言いましたがこれは
グローバル変数と引数だけです。
なので短くすることを求めるならセミコロンがいらない引数の方で宣言しがほうが良い。
と、言いたいところですが実際そうでもない。グローバル変数の方が良かったりすることもある。それについては後で。
さてまだまだ縮みます。
- returnされた0なんて使ったことなんて無い、いらないんじゃね?
- gccは想像以上に優秀だから宣言したときに初期化してくれる。
- for文が埋まってなきゃいけない理由なんてないぜ!for(;;)でも問題ない!
return 0による縮みが大きいですね。AOJとかPKU側はreturn 0を推奨してるようですが、
推奨なんで絶対ではない。省き放題でござる。
それでも0を返したい人はexit(0);をしましょう。1B減ります。
さて、a=1はなくなってるのにb=1はなくなってないと思ってる方がいるでしょう。
gccは宣言時に初期化してくれますが、実はこれはグローバル変数だけです。 そして値は0です。
じゃあなんでa=1はなくていいのかというと、gccではmain関数実行時に引数1を与えています。
つまりaは初期化ではなくて代入です。第一引数として1を受け取っています。
そのかわりbは初期化されてないので、初期化しないといけません。
それに0で初期化したいときはこれは不都合です。セミコロンは我慢してグローバル変数で宣言しましょう。
とりあえず仕様的な短縮はこれまでです。
ここからは技術的に短縮しましょう。
- for文が2つっていうのが冗長に感じるお(^ω^)
- b%=9の返り値はb%9であーる
- ++bの返り値はb+1であーる
- ||(or)は左の値が真なら右の値を参照とか実行とかしないお(^ω^)
はい、これでわりと縮んでます2B縮んでます69Bです
このコードをみて何やってるのか一発でわかった方はショートコーダーもしくは変態。
中で何をやってるのかというと
-
- 1 .a=1,b=0で初期化
- 2 .aが9より大きかったら終了
- 3 .[a]×[b+1]=[a×(b+1)] を出力 一度だけ++bをしてるのでbは1増える
- 4 .bにbを9で割ったあまりを代入、 もし0ならaの値を1増やす
- 5 .2へ戻る
ということをやっております
おそらく一番引っかかるのは3番つまり("%dx%d=%d\n",a,++b,a*b+a)にあたるところでしょう。
++bでbは一増えてるのになぜa*bではなくa*b+aなのか
これは大きな理由はCの副作用完了点という仕様です。
副作用完了点というのは、副作用(つまり変数に施される処理)がいつ完了するのかというものです。
gccでは式の終わりが副作用完了点です。変数の代入も実行した関数による副作用もすべて文が終わったときに完了します。
今回の("%dx%d=%d\n",a,++b,a*b+a)は3つ目の%dに対応するa*b+aが参照される時 というのはまだ++bの副作用が完了していません。
つまり2つ目の%dがに対応する++bが参照された時++b自体は(b+1)という値を返してますがb=b+1の処理は実行されてません。
なのでa*b+aはa*bではいけないのです。
実はこのコードあと少し、縮めることができます。 今回の記事の知識の範囲内でさらに縮めることができます。
挑戦してみてください。