メインページに戻る
Japan Blog

ダイバーシティ & インクルージョン

Google のソフトウェアエンジニアとTシャツ



一言で 「Google T シャツ」 と言っても、色々なバリエーションがあります。

Google Store で販売している T シャツだけでなく、イベントやプロジェクトの立ち上げ時など、色々なタイミングでオリジナルの 「Google T シャツ」 が作られます。少し前のことになりますが、本社の屋上にソーラーパネルを張り巡らせたことを公表したときには、ソーラーパネルの描かれた記念 T シャツが本社中庭で配布されていました。このような限定 「Google T シャツ」 はそのときにしか作られません。レアなのです。

東京オフィスでもそのような T シャツを作ることがたびたびあります。今回はそのうちの一つとして、エンジニアが作った T シャツをご紹介します。

「Google」のロゴとC言語でのメッセージが載せてあるホワイトTシャツを示す画像。

これはエンジニアのオフサイト ( アウトドアイベントを通じて日本のエンジニア同士が交流するイベント ) 記念に作られたものです。でも、オフサイトと関係のない謎の文字列が並んでいます。一体この文字列は……

b;main(){printf("g%sgle",memset(&b,111,atoi(gets())));}

実はこれ、れっきとした C 言語のプログラムです。言語標準に完全に準拠しているわけではありませんが、Linux の gcc では動作します。エンジニアの S.H さんにお願いして書いていただきました。

( コンパイラや実行環境によっては、プログラムだけでなく OS にも悪影響を及ぼす可能性があるので、実際に実行するときには自己責任でお願いします )

では、これは何をするプログラムでしょうか。

このようなプログラム、およびそれを書く行為は、俗に 「コードゴルフ」 と呼ばれています。「与えられた問題に大していかに少ないバイト数で問題を解けるか」 という一種の遊びで、ハッカーの伝統的なスポーツ、とさえ言われています ( ただし、あまり痩せません ) 。http://codegolf.com/http://golf.shinh.org/ が有名な「ゴルフ場」です。

上記のプログラムは 「数値を入力として受け取って、その数値分だけ 'o' を挟んだ "gooo...ogle" という文字列を出力してください」 という問題に対する 「コードゴルフ」 の結果です。

$ cat google.c
b;main(){printf("g%sgle",memset(&b,111,atoi(gets())));}
$ gcc google.c
( 警告が出ますがエラーにはなりません )
$ ./a.out
15
gooooooooooooooogle

T シャツ作りにも Google のエンジニアらしさが現れているのでした。

興味のある方もいらっしゃるかと思いますので、上のプログラムがなぜ動作するのかについて説明します。

まず、全体としては以下のように動作することを意図しています。

  • gets() によりユーザからの入力を受け取る。
  • atoi() で gets() の結果を整数に変換 ( ここではその整数をNとする )
  • memset() で変数 b のアドレスに 111 すなわち char 型で言う 'o' を整数 N 分書き込む。
  • printf() で goo...gle を出力。

このコードが実際にコンパイルされ、意図通りに動作するかは、実行する環境に依存します。細かい点を説明すると、大体以下の通りになります。

  • バイト数を減らすため、stdio.h, string.h に対する include 節が省略されています。
  • 冒頭の "b" は int 型のグローバル変数宣言です。C 言語では仕様により、型名を省略した変数は int 型とみなされます。この規則を利用してバイト数を減らしています。
  • main() の引数も戻り値はなくても動作するので省略されています。
  • gets () は本来引数をひとつ受け取る関数ですが、やはり省略されています。この場合、実行時に gets() がどのようなポインタを受け取るかは未定義ですが、 ここでは 「偶然書き込み可能なメモリ領域へのポインタが渡されていて、ユーザから与えられた文字列が短い」 という条件がそろった時に動作します。結局、実 際に動作するかどうかは環境依存です。
  • 111 は ASCII コードの 'o' を意味します。111 も 'o' も 3 バイトでプログラムのサイズは変わりませんが、見づらくなるように敢えて 111 となっています。  
  • memset() で b へのポインタが指すメモリ領域に整数 N の分だけ 111('o') を書き込んでいます。N が size(int) の値より大きいときにはオーバーフローしますが、与えられた数値がそれほど大きくなければ、オーバーフローしても一応動作します。

私の手元の Linux 環境では入力された値が 2000 程度までは大丈夫でした。別の環境では 4000 程度まで大丈夫だったり、逆にまったく動かなかったりするようです。やはり環境依存な部分が多々あります。

コードゴルフで書かれるプログラムは、そのプログラムが実行される環境に強く依存した形で書かれることが多く、仕事で書くようなプログラムにはあまり向きません。あくまで趣味の領域で愉しむことですね。

もちろん、Google 社内で仕事のプログラムを書くときには、誰もこのような書き方はしませんのでご安心を :-)