Edit
C言語とは?

C言語(Cげんご)は、1972年にAT&Tベル研究所のデニス・リッチー (Dennis M. Ritchie) が主体となって作ったプログラミング言語である。英語圏では単に C と呼称されており、日本でも文書や文脈によっては同様に C と呼称される。UNIXの移植性を高めるために開発された経緯から、オペレーティングシステムカーネル向けの低レベルな記述ができることを特徴としている。

*演算子

Edit
ビット演算子

役割表記
AND'&'
OR'|'
XOR'^'
NOT'~'
LEFT'<<'
RIGHT'>>'

Edit
データ型

Edit
const

変更不可能な変数の宣言を行う。

const int iNumber;

Edit
static

変数の保存エリアを静的なものにする。ローカル変数の宣言にstatic を付けると、プログラム開始時にメモリに記憶され、関数を終了しても保持している値が消えることがなくなる。静的グローバル変数は、変数のスコープが、そのソースファイルだけに限定される。

static int globalNumber;

静的関数の意味は、静的グローバル変数と同じで、そのソースファイル内からしかアクセスできないようにする

※:GCC-4.0になってから、グローバルシンボルと同じ名前のstaticシンボルを使うとエラーにするように変更された。

Edit
extern

コンパイラに変数が対象ソースの外部で宣言されている、または外部から利用することを教える。externを利用するには以下の条件がある。

  1. externのついた広域変数は必ずどこかのモジュールに実体が必要となる。
  2. externのつかない広域変数は基本的にexternされているのと同じような振る舞いをする。但しモジュールに実体がなければリンカが実体を作る。
  3. 初期化指定があれば、変数は必ず実体を作る。

※同じ名前の広域変数は自動共有され、共有を意図していない場合にはバグの温床となる。それゆえソースをまたがって共有される広域変数には、必ずextern指定を付けることを心がける。

Edit
volatile

コンパイラの最適化を抑制する装飾語。特に制御系のソースにおいて、参照するポインタがCPUの処理がシーケンスで、割り込まれないことを前提としているアプリケーションなどの場合には問題がないが、参照先のポインタが割り込み処理などによって、値が変化する場合、コンパイラの最適化処理によって、アプリ内の値を参照し判断する処理の位置が、コンパイラによって変化した場合、処理が予想通りに行われない場合が発生する。そのような場合にこの装飾語が利用される。
詳しくはここのサイトを参照の事

Edit
assert(アサート)

デバッグ段階でエラーを検出するために、ソース中に埋め込んでおく実行文。C言語には、assert()というマクロが用意されており、引数に条件式を渡す。

例:void assert( number == 100 );

この条件式が偽であるときにassert() の部分で処理停止させ、該当箇所の情報を出力して知らせることで、デバッグを補助する。

Edit
その他の特殊な命令

Edit
__multi_interrupt

CA850では、割り込みハンドラの指定を“#pragma interrupt指令”および “__interrupt修飾子”(通常の割り込みの場合)、または“#pragma interrupt指令”および“__multi_interrupt修飾子”(多重割り込みの場合)で行います。以下に、割り込みハンドラの記述例を示します。
例1) ノンマスカブル割り込みの場合

#pragma interrupt NMI func1     /* ノンマスカブル割り込み*/
__interrupt
void func1(void)
{
    :
}

例2) 多重割り込み指定の場合

#pragma interrupt INTP0 func2
__multi_interrupt               /* 多重割り込み関数指定*/
void func2(void)
{
    :
}

Edit
定義済みマクロや特別定義

Edit
システム定義

区分コード意味
C言語__DATE__ソースのコンパイル日付
__TIME__ソースのコンパイル時刻
__FILE__ソースのファイル名
__TIMESTAMP__ソースの保存日時
__func__関数名(Visual Studio.NET以降では、__FUNCTION__)
__LINE__行番号
__STDC_VERSION__C言語のバージョン
C++__cplusplusC++ソースとしてコンパイルしようとするときに定義されている
ARM__CC_ARMコンパイラ識別用(コンパイラ名)
__ARMCC_VERSIONコンパイラバージョン
__armarmcc, tcc, armcpp, tcpp を使用している場合に定義される。
__BIG_ENDIANビッグエンディアン向け環境で定義される。
__embedded_cplusplusEC++ モード時に定義される。
__sizeof_intプリプロセッサ版 sizeof(int)
__sizeof_longプリプロセッサ版 sizeof(long)
__sizeof_ptrプリプロセッサ版 sizeof(void*)
Cygwin__CYGWIN__コンパイラ識別用
GNU C__GNUC__コンパイラ識別用
.NET_M_IX8632ビット、x86環境。
_M_X6464ビット、x64環境。
_MFC_VERMFCのバージョン。

※詳しくはこのページを参照の事

Edit
C++との連携について(extern "C")

C++とC言語とでは、コンパイル後のリンクできる形となったオブジェクトファイル(.o の拡張子のもの、リンカーで利用する)では、関数名の管理において、それぞれ別の概念で関数名が管理される。C言語の場合、1つのソースで作成した関数に同じ名前を付けられないため、オブジェクトファイルの状態では関数名がそのままリンク時の名前に利用される。しかしC++の場合、同じ名前の関数をオーバーロードできる機能があるため、関数名を識別するためにC++が勝手に関数名の後ろに文字列を付加している。そのため、そのままではリンクエラーが発生する。(Cなどのコンパイラにとって、実際の実行時において関数名の名前に意味が無いためこのような仕様となっている)

そこで、C側のソースには、C++がコンパイル時に初期値として定義している、__cplusplus 定義文を判断して、extern "C" 構文をextern 関数に設定することで、その問題を回避できる。

#ifdef __cplusplus
extern "C" {
#endif

extern int function();

#ifdef __cplusplus
}
#endif

この例では、function関数の extern をC言語での関数定義として、処理するように定義の範囲を{ } で括ることで、C++のコンパイラでも正常にコンパイルできるようにしている。通常、C/C++ のコンパイラを利用する場合には、このような配慮をしておくことが必要である。

Edit
C言語テクニック

Edit
SOファイルサイズの縮小や速度向上について

gcc4以降から、visibility supportという機能が追加されており、通常C言語では他の言語と違い、関数名などのシンボリックはすべて公開を基準としているため、SOファイルには基本すべてのシンボリックが登録されるという、変な仕様になっているが、このシンボリックを、関数名の頭に下記のように設定すると、登録(公開)・非登録(非公開)の設定ができる。

__attribute__ ((visibility("default"))) void 公開関数( void ){}
__attribute__ ((visibility("hidden")))   void 非公開関数( void ){}

というように、ライブラリへの登録関数の設定ができ、これによってSOファイルのサイズが、5〜20%小さくなり、SOの最初のロード時間も非公開にしたぶん、高速化される。

Edit
コンパイラが自動的に設定する定数

定義名概要
__LINE__現在の行番号
__FILE__コンパイルされているファイル名
__DATE__コンパイル時の日付 ( 月/日/年 )
__TIME__コンパイル時の時間 ( 時:分:秒 )
__func__現在の関数名

Edit
ワーニング(Warning: 'visibility' attribute ignored)

この可視属性の 擬似命令はgcc 3.3以降でサポートされているため、GCC 3.2 以前のバージョンでコンパイルすると、上記のワーニングとなる。

Edit
C++

Edit
Vectorクラス

Edit
GCCのコンパイルオプション

Edit
-f(no-)omit-frame-pointer(コピペ)

関数のスタックフレームに関する処理を省略可能にするか。

x86で言えば、スタック操作は通常ebp経由で行われるため、関数先頭で以下のアセンブリコードが出力される。

# AT&T形式

   push %ebp       # ebpを待避
   mov  %esp,%ebp  # スタックアドレスをebpで固定

# intel形式

   push ebp        # ebpを待避
   mov  ebp,esp    # スタックアドレスをebpで固定

逆に関数の末尾ではpop ebpが行われ、スタック(esp)とebpを復元する処理が入る。

これらを省くことで、特にスタックフレームの生成コードが割合的に大きくなるような、小さな関数ではコードが速く小さくなることがある。この場合スタックにはesp経由でアクセスするようになるが、espのアドレッシングモードが豊富ではないことから、却って遅く大きくなることもあるので注意。

CPUが異なれば効果も異なり、-O2で自動的に仮定されるプラットフォームもある模様。

Edit
GCCの便利コマンド

gccの検索パスを表示

# gcc -print-search-dirs

Edit
gccのソースインストール

# wget https://gmplib.org/download/gmp/gmp-6.1.2.tar.bz2
# tar xf gmp-6.1.2.tar.bz2
# cd gmp-6.1.2
# ./configure
# make
# make install
# wget http://www.mpfr.org/mpfr-current/mpfr-3.1.6.tar.bz2
# tar xf mpfr-3.1.6.tar.bz2
# cd mpfr-3.1.6
# ./configure  --with-gmp-lib=/usr/local/lib --with-gmp-include=/usr/local/include
# make
# make install
# wget ftp://ftp.gnu.org/gnu/mpc/mpc-1.0.3.tar.gz
# tar xf mpc-1.0.3.tar.gz
# cd mpc-1.0.3
# ./configure --with-gmp-lib=/usr/local/lib --with-gmp-include=/usr/local/include --with-mpfr-lib=/usr/local/lib --with-mpfr-include=/usr/local/include
# make
# make install
# wget http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-5.5.0/gcc-5.5.0.tar.gz
# tar xf gcc-5.5.0.tar.gz
# cd gcc-5.5.0
# ./configure --program-suffix=-5.5 --with-gmp=/usr/local --with-mpfr=/usr/local --with-mpc=/usr/local
# make
# make install

※この --program-suffix をつけておくと、gccコマンドを上書きせず、gcc-5.5 というコマンドを生成してくれるので、後でシンボリックリンク等を使うと良い。