Windows Tiny C Compiler
Windows版 Tiny C Compiler でexe(GUI)を作成する
組み込み用途向けCコンパイラ「Tiny C Compiler」がVer.0.9.26から64bit版Windowsに対応したようなので、64bit版(x64版)のexeファイルを作成してみた。
ダウンロードサイズが500KB足らずという超コンパクトなコンパイラなのに、windows.hなどが用意されており、Win64APIが叩けるのが面白い。
Windowsネイティブのプログラムが作成できるC言語開発環境の中では、私が知る限り最短で構築できて最小サイズだと思う。
インストールも不要なので、USBメモリに入れて持ち運び、そこにあるPC上でCをコンパイル&リンクすることができてしまう。
「Tiny(とても小さな)」を名乗っているだけあって、C++はコンパイルできなかったり標準ライブラリでも一部の関数は使用できないものがあったりするので、その点は注意が必要だ。
ダウンロードして解凍するだけなので、環境構築と呼べるほどのものではないが以下手順。
1. Tiny C Compilerをダウンロードする
- https://bellard.org/tcc/ からWindows(win64)版をダウンロードしてくる(Download → tcc-0.9.27-win64-bin.zip リンクをクリック)
- 適当なフォルダに解凍する
- 解凍したフォルダ内に「tcc.exe」があることを確認しておく
2. ソースリストを作成する
とりあえずGUIのHello worldを書いてみる。
「hello.c」とか名前を付けて、Shift-JISで保存する。(UTF-8とかだと日本語が化ける)
3. コンパイルする
「hello.c」を「tcc.exe」にドラッグアンドドロップする。
それだけ。
4. 実行してみる
同フォルダ内にできた hello.exe をダブルクリックする。
メッセージボックスが表示され、その中に「Hello tiny world.」その下に「OK」ボタンが出てくれば成功。
以下、補足です。(補足のほうが長い)
サンプルプログラムについて
Tiny C Compilerを解凍したフォルダ内に「examples」というフォルダがある。
この中に「hello_win.c」というソースがあるので、まずはそれをコンパイルしてみるのがいいかもしれない。
CreateWindow関数でウィンドウを生成し、GetMessage関数でメッセージを取得、DispatchMessage関数でウィンドウプロシージャへメッセージを送出、ウィンドウプロシージャでメッセージを受け取って処理を振り分ける、というWindowsでGUIプログラミングをする際の基本が詰まっている。
Win64APIを直接叩いてウィンドウを表示してみたい人は、この hello_win.c を読むのが早道だと思う。
コンパイルについて
上では、ソースファイルを tcc.exe にドラッグ&ドロップするだけと説明したが、この方法ではエラーが出た時に気づけないので、ちゃんとプログラミングをしたいときはコマンドプロンプトから、-Wwarningオプションを付けてコンパイルするようにしたほうがいい。
上の hello.c をコンパイルする時は cmd.exe を起動して、
例)「D:\prog\tcc\」にTiny C Compilerを解凍していて、同フォルダ内に hello.c を作成した場合
d:(エンター)
cd \prog\tcc(エンター)
tcc -Wwarning hello.c(エンター)
とすれば、エラーやワーニングを確認できる。
とはいえ可能な限り小さくするためか、エラーメッセージは簡素な感じがするし、ワーニングもかなり重要なもの以外は何も言ってこない。
例えばchar変数に500とかを代入しようとしても沈黙しているので、バグには気づきくい感じがする。
エラーが無ければ(というか何も出なければ)コンパイル(&リンク)が正常にできている。
tcc フォルダ外にソースファイルを作成したい場合は、以下のようにして tcc フォルダにパスを通しておけばOK。
1. スタートボタン右クリック→「システム」をクリック
2. 「システムの詳細設定」をクリック
3. 「環境変数」をクリック
4. 「Path」をクリック
5. 「編集」をクリック
6. 「参照」をクリック
7. 上の例でいえば D:\prog\tcc を開いて「OK」をクリック
コンパイル後のファイルサイズについて
例えばMinGW-w64で上の hello.c をコンパイルすると、exeファイルのサイズが約55KBになるのに対して、Tiny C Compilerでコンパイルすると約3KB、わずか18分の1というサイズになってしまう。
コンパイルして生成されたexeファイルのサイズも「Tiny」だ。
この辺りはさすがの組み込み用途向けだと感じる。
扱える配列サイズについて
例えばスタック上に配列を作成する際、あまり大きなサイズを確保しようとするとそこで処理が止まってしまったり、その後の動作中に落ちてしまうことがある。
具体的なサイズはコードの内容やOSのコンディションなどによるのかもしれないが、char型配列単体だと大体100KBを超えて確保しようとするとダメなことが多い。
この辺りも組み込み用途向けという感じがする。
win64版のみにある挙動(バグ?)
win64版のみ、API関数 or 配列回りにどうもよく分からない挙動がある。→ Ver.0.9.27で修正されたようでこの挙動は起きなくなった。
例えば、こういったコードを書いてみた。
デバイスコンテキストを使った画面描画でウィンドウ内を三角形が形を変えながら動き続けるだけの簡単なプログラムなのだが、win32版でコンパイルすると問題なく動くのに対し、win64版でコンパイルすると三角形にならず、細い線のようになってしまう。
chy[]の値がウィンドウ外の遥か彼方の領域を指してしまっているようだ。
いろいろ調べてみた結果、裏画面から表画面へ転送する際の BitBlt() 関数を実行した後にchy[]が破壊されている感じがする。
/*
* 裏画面から表画面へ転送
*/
BitBlt(hdcf, 0, 0, rect.right, rect.bottom, hdc, 0, 0, SRCCOPY);
↑この部分だ。
BitBlt() 関数実行直前は 301 だった chy[0] の値が、 実行直後には 13369376 といったような値になっている。
win32版でコンパイルするとchy[]の値は変化しないのだが、win64版でのみこのような挙動になるようだ。
これが仕様なのかバグなのかはよく分からないが、MinGW-w64でコンパイルすると正常に動くので、バグなのかもしれない。(結局バグだったようだ。Ver.0.9.27で修正された)
64bitにこだわりさえしなければ、32bit版のほうが安定しているような感じがする。
ちなみにこの挙動を確認した後はWindowsを再起動しておいたほうがいいと思う。
データ型モデルなどについて
Tiny C Compiler(win64版)の型のサイズは以下のようになっている。
- char : 8bit (-128~127)
- short : 16bit
- int : 32bit
- long : 32bit
- long long : 64bit
- float : 32bit
- double : 64bit
- long double : 64bit
LLP64を採用しているようで、long型は32bitとなる。
Microsoft VC++に合わせてあるようだ。
64bitの値を扱いたい時はlong long型にする必要がある。
char型の範囲は-128~127なので、これもVC++に合わせてあるようだ。
0~255で扱いたい時はunsigned charを使う必要がある。
ただ、long doubleが64bit(8byte)なので、VC++やMinGW-w64などと比べると半分しかない。
この点は注意が必要かもしれない。
|