C言語(Cげんご)は、1972年にAT&Tベル研究所のデニス・リッチー (Dennis M. Ritchie) が主体となって作ったプログラミング言語である。英語圏では単に C と呼称されており、日本でも文書や文脈によっては同様に C と呼称される。UNIXの移植性を高めるために開発された経緯から、オペレーティングシステムカーネル向けの低レベルな記述ができることを特徴としている。
*演算子
役割 | 表記 |
AND | '&' |
OR | '|' |
XOR | '^' |
NOT | '~' |
LEFT | '<<' |
RIGHT | '>>' |
変更不可能な変数の宣言を行う。
const int iNumber;
変数の保存エリアを静的なものにする。ローカル変数の宣言にstatic を付けると、プログラム開始時にメモリに記憶され、関数を終了しても保持している値が消えることがなくなる。静的グローバル変数は、変数のスコープが、そのソースファイルだけに限定される。
static int globalNumber;
静的関数の意味は、静的グローバル変数と同じで、そのソースファイル内からしかアクセスできないようにする
※:GCC-4.0になってから、グローバルシンボルと同じ名前のstaticシンボルを使うとエラーにするように変更された。
コンパイラに変数が対象ソースの外部で宣言されている、または外部から利用することを教える。externを利用するには以下の条件がある。
※同じ名前の広域変数は自動共有され、共有を意図していない場合にはバグの温床となる。それゆえソースをまたがって共有される広域変数には、必ずextern指定を付けることを心がける。
コンパイラの最適化を抑制する装飾語。特に制御系のソースにおいて、参照するポインタがCPUの処理がシーケンスで、割り込まれないことを前提としているアプリケーションなどの場合には問題がないが、参照先のポインタが割り込み処理などによって、値が変化する場合、コンパイラの最適化処理によって、アプリ内の値を参照し判断する処理の位置が、コンパイラによって変化した場合、処理が予想通りに行われない場合が発生する。そのような場合にこの装飾語が利用される。
詳しくはここのサイトを参照の事
デバッグ段階でエラーを検出するために、ソース中に埋め込んでおく実行文。C言語には、assert()というマクロが用意されており、引数に条件式を渡す。
例:void assert( number == 100 );
この条件式が偽であるときにassert() の部分で処理停止させ、該当箇所の情報を出力して知らせることで、デバッグを補助する。
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) { : }
区分 | コード | 意味 |
C言語 | __DATE__ | ソースのコンパイル日付 |
__TIME__ | ソースのコンパイル時刻 | |
__FILE__ | ソースのファイル名 | |
__TIMESTAMP__ | ソースの保存日時 | |
__func__ | 関数名(Visual Studio.NET以降では、__FUNCTION__) | |
__LINE__ | 行番号 | |
__STDC_VERSION__ | C言語のバージョン | |
C++ | __cplusplus | C++ソースとしてコンパイルしようとするときに定義されている |
ARM | __CC_ARM | コンパイラ識別用(コンパイラ名) |
__ARMCC_VERSION | コンパイラバージョン | |
__arm | armcc, tcc, armcpp, tcpp を使用している場合に定義される。 | |
__BIG_ENDIAN | ビッグエンディアン向け環境で定義される。 | |
__embedded_cplusplus | EC++ モード時に定義される。 | |
__sizeof_int | プリプロセッサ版 sizeof(int) | |
__sizeof_long | プリプロセッサ版 sizeof(long) | |
__sizeof_ptr | プリプロセッサ版 sizeof(void*) | |
Cygwin | __CYGWIN__ | コンパイラ識別用 |
GNU C | __GNUC__ | コンパイラ識別用 |
.NET | _M_IX86 | 32ビット、x86環境。 |
_M_X64 | 64ビット、x64環境。 | |
_MFC_VER | MFCのバージョン。 |
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++ のコンパイラを利用する場合には、このような配慮をしておくことが必要である。
gcc4以降から、visibility supportという機能が追加されており、通常C言語では他の言語と違い、関数名などのシンボリックはすべて公開を基準としているため、SOファイルには基本すべてのシンボリックが登録されるという、変な仕様になっているが、このシンボリックを、関数名の頭に下記のように設定すると、登録(公開)・非登録(非公開)の設定ができる。
__attribute__ ((visibility("default"))) void 公開関数( void ){} __attribute__ ((visibility("hidden"))) void 非公開関数( void ){}
というように、ライブラリへの登録関数の設定ができ、これによってSOファイルのサイズが、5〜20%小さくなり、SOの最初のロード時間も非公開にしたぶん、高速化される。
定義名 | 概要 |
__LINE__ | 現在の行番号 |
__FILE__ | コンパイルされているファイル名 |
__DATE__ | コンパイル時の日付 ( 月/日/年 ) |
__TIME__ | コンパイル時の時間 ( 時:分:秒 ) |
__func__ | 現在の関数名 |
この可視属性の 擬似命令はgcc 3.3以降でサポートされているため、GCC 3.2 以前のバージョンでコンパイルすると、上記のワーニングとなる。
関数のスタックフレームに関する処理を省略可能にするか。
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で自動的に仮定されるプラットフォームもある模様。
gccの検索パスを表示
# gcc -print-search-dirs
# 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 というコマンドを生成してくれるので、後でシンボリックリンク等を使うと良い。