L'Isola di Niente
L'Isola di Niente » C and GLib Tips » gcc で C/C++

gcc で C/C++

Linux 環境で gcc を使って C 及び C++ 言語のビルド方法と注意点。
C 言語そのものは解説しません、本でも買ってください。

本当は Anjuta あたりを使うのが一番簡単だと思いますが…
(筆者は使っていませんが)
基本は大切なのであえて端末や gedit でコンパイルする方法を解説。

C 言語のコンパイル

/* testc.c */
#include <stdio.h>

int
main (int argc, char *argv[]) {
	printf("はろーわーるど\n");
	return 0;
}
日本語を出力する何の変哲もない C 言語コードを書き test.c という名で保存。
リテラルに日本語を使う場合は LANG と同じ文字コードで保存されている必要がある。
LANG は下記コマンドで確認できます。
echo $LANG
#=>ja_JP.utf8
エディタの保存文字コードが気になる方は cat や less コマンドで確認すると良い。
LANG と一致しているなら文字化けせずに表示できます。
コンパイルするには端末を起動してそのディレクトリに cd コマンドで移動します。
gcc ファイル名
と打ち込むと a.out というファイルが作られます。
コンパイルが成功すると何も表示されないということに注意してください。

実行パーミッション +x も付いているのでそのまま a.out を実行できる。
ただし当然パスは通っていないので「./」を付加。

img/gcc01.png
文字コードが違う場合もコンパイルは通りますが文字化けします。
Windows からソースコードを持ってきた場合 iconv 等で変換しましょう。

コードに間違いがあるとコンパイルエラーになり行番号付きでエラーが出力されます。
以下は printf の最後にセミコロンを入れ忘れた場合。

img/gcc02.png

コマンドラインオプション

この方法だけでは全部 a.out という名前になってしまいます、-o オプションで別の名前を付けられます。
Windows ではないので exe の拡張子は不要です、実行パーミッションのみで動きます。
たとえば hello という名前にしたければ
gcc -o hello test_c.c
他のオプションについては以下(他人のサイト)を参照、又は各自で検索してください。

Using and Porting the GNU Compiler Collection (GCC) - GCCコマンド・オプション

分割コンパイル

テストとして以下 2 つのファイルを用意します。
/* func.c */
int plus (int x){ return x + x; }
/* main.c */
#include <stdio.h>

int
main (int argc, char *argv[])
{
    printf ( "%d\n", plus(3) );
    return 0;
}
後は gcc func.c main.c のようにソースコードを全部指定する。
gcc *.c のようにワイルドカードを使うのが簡単。
とにかくオブジェクト同士が合体して func.c で定義した関数が利用できるようになる。

グローバル変数を参照したりする場合はヘッダを作り extern 宣言等をして使います。
ヘッダついては[インクルードガード]で検索してください、ヘッダには型のみ記述すべし。
#pragma once が実は gcc でも使えるんですけどね。

C++ 言語のコンパイル

C++ 言語のコンパイルは g++ コマンドを使います。
class, STL 等は C++ 標準なので当然 Linux からも利用できます。
iostream.h と書いている古い本等がありますが C++ ヘッダに拡張子はありません。
// stl.cc
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
 
using namespace std;

template <class T>
struct out : public unary_function<T, void> {
    void operator()(T n) {
        cout << n * 10 << ' ';
    }
};
 
class Test {
public:
    Test() {
        vector<int> vec;
        for (int i=0; i < 10; i++) {
            vec.push_back(i);
        }
        for_each(vec.begin(), vec.end(), out<int>());
    }
};
 
int
main(int argc, char* argv[]) {
    Test* t = new Test();
    cout << endl;
    //=> 0 10 20 30 40 50 60 70 80 90
    delete t;
    return 0;
}
GNU 界隈では cc という拡張子が一般的なようです。
Windows では cpp で他に cxx もよくある、つまり何でもいい。

img/gcc03.png

STL を使っても何のオプションも不要でビルド可能です。

Makefile

# Makefile
exefile: testc.c
    gcc -o exefile testc.c


という内容でファイル名を Makefile にしたものをソースと同じディレクトリに置きましょう。
注意としてインデントは \t で行うのを忘れないように。
そして端末から make コマンド

img/gcc04.png

また Gedit の外部ツールを有効にして「ビルド」を実行(Ctrl+F8)なんてこともできます。
Makefile の書き方については以下(他人のサイト)を参照してください。

Makefileの書き方 - スキルアップ輪講

C99

現行 gcc は標準で部分的に C99 に対応しています(// コメント等)
-std=c99 オプションを付けることによりフル対応可能。
c99 というラッパースクリプトもある。
#include<stdio.h>

// gcc -std=c99 hoge.c
// or
// c99 hoge.c

int
main (int argc, char *argv[]) {
    //int i;
    //for (i=0; i<3; i++) {
    for (int i=0; i<3; i++) {
        printf("%d\n", i);
    }
    return 0;
}

Trigraph, Digraph

Trigraph は昔コンピューターで表記できる文字が少なかった時代に規定された三文字表記。
日本語キーボードは恵まれていますがコレが無いと困る言語圏もあったのです。
トライグラフ - Wikipedia
??=include <stdio.h>

/*
 * -trigraphs オプションにて利用可能
 * gcc -trigraphs hoge.c
**/
 
main() ??<
    printf("%s??/n", "はろーわーるど");
??>

Digraph は C99 で規定されたチョッピリ洗練版。
gcc はオプション無しで使える。
%:include <stdio.h>
 
main() <%
    printf("%s\n", "はろーわーるど");
%>

現在は中括弧キー等が無い言語圏でもすべて右 Alt キー経由で入力できるようです。
ということで歴史の長い C 以外の言語ではンなことできませんのであしからず。

GLib

GNOME 関連アプリのソースコードを見ると printf や char なんて使われていません。
GLib によるマクロ g_print や gchar で記述されている。
様々な理由がありますが GLib に少しでも係るアプリを作るならこちらを使いましょう。

GLib ヘッダを include するには pkg-config 指定が必要です。
`pkg-config --cflags --libs glib-2.0`
GLib には日本語を扱うのに便利な関数も用意されている。
#include <glib.h>

/* gcc test.c `pkg-config --cflags --libs glib-2.0` */

int
main (int argc, char *argv[]) {
    /* 日本語を含む文字列 */
    gchar c[] = "Linux 勉強中";
    /* 漢字も一文字として長さを得る */
    g_printf ("%s は %ld 文字です\n", c, g_utf8_strlen(c, sizeof(c)));
    /* UCS4 に変換 */
    GError * error;
    gunichar * ucs;
    glong len;
    ucs = g_utf8_to_ucs4 (c, -1, NULL, &len, &error);
    /* エラーチェック */
    if (!ucs) {
        g_print (error->message);
        gint retval = error->code;
        g_error_free (error);
        return retval;
    }
    /* 一文字づつ書き出し */
    gint i = 0;
    for (i; i<len; i++) {
        gchar * cc = g_malloc0(sizeof(gunichar));
        g_unichar_to_utf8 (ucs[i], cc);
        g_printf ("%s\n", cc);
        g_free(cc);
    }
    g_free(ucs);
    return 0;
}
日本語等を扱う wchar_t のサイズが Windows とは違うことに注意。
Windows(TCHAR) では UTF-16(2byte) ですが gunichar は UCS-4(4byte) です。
これ以上細かいことはリファレンスマニュアルを参照ください(英語)。
GLib Reference Manual

x86_64

64bit アプリケーションではポインタサイズが 64bit(8byte) になる。
wchar_t のサイズが Windows とは違う他に 64bit では long も変わる。
#include<stdio.h>
#include<stdlib.h>

int
main (int argc, char *argv[]) {
    int * p;
    printf ( "int     = %lu\n", sizeof(int) );
    printf ( "long    = %lu\n", sizeof(long) );
    printf ( "pointer = %lu\n", sizeof(p) );
    printf ( "char    = %lu\n", sizeof(char) );
    printf ( "wchar_t = %lu\n", sizeof(wchar_t) );
    printf ( "size_t  = %lu\n", sizeof(size_t) );
    return 0;
    
    /* output
    Linux x86_64 | Windows x64
                 |
    int     = 4  | int     = 4
    long    = 8  | long    = 4
    pointer = 8  | pointer = 8
    char    = 1  | char    = 1
    wchar_t = 4  | wchar_t = 2
    size_t  = 8  | size_t  = 8
    */
}
なので Linux なら long 変数にポインタを突っ込...
バグの元なのでヤメて注意しましょう。

ちなみに Mac OS X は 64bit の UNIX ベースなので Linux と同じ結果になる。

GTK+

GTK+ ヘッダを include するにはやはり pkg-config 指定が必要です。
コンパイル毎に打ち込みなんてアホクサイので Makefile を利用しましょう。
# Makefile
gtkexe: test_gtk.c
	gcc -o gtkexe test_gtk.c `pkg-config --cflags --libs gtk+-3.0`
※上記は GTK3 です、GTK2 の場合は gtk+-2.0 にする
※gtk+ により glib, gio はインクルードされるので別途指定は不要


そして肝心なコード、ここでは GtkWindow を表示するだけの最小限サンプル。
#include <gtk/gtk.h>

int
main(int argc, char *argv[]) {
    GtkWidget *window;
    /* 初期化必須 */
    gtk_init (&argc, &argv);
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    g_signal_connect (G_OBJECT (window), "delete_event", gtk_main_quit, NULL);
    gtk_widget_show_all (window);
    gtk_main ();
    return 0;
}
C 言語なので PyGtk のようなメソッドではなく関数をひたすら利用していきます。
それと GTK+ 初期化関数の呼び出しは必須なので忘れないように。
これ以上細かいことはリファレンスマニュアルを参照ください。
GTK+ 3 Reference Manual
Copyright(C) sasakima-nao All rights reserved 2002 --- 2017.