忘れがちなC言語

# ■ プリプロセッサ

## define - プリプロセッサマクロ定義
~~~c
#include <stdio.h>
#define COUNT                  0x5
#define MULTIPLE_COUNT         (2 * COUNT)
#define DEVIDE_COUNT(x, y)     ((x) / (y))

int main()
{
    printf("%d\n", COUNT);
    printf("%d\n", MULTIPLE_COUNT);
    printf("%d\n", DEVIDE_COUNT(9, 2));
}
~~~

~~~c:実行結果
5
10
4
~~~

## 既定義マクロ
~~~c
#include <stdio.h>

int main()
{
    printf("LINE : %d\n", __LINE__);
    printf("FILE : %s\n", __FILE__);
    printf("DATE : %s\n", __DATE__);
    printf("TIME : %s\n", __TIME__);
}
~~~

~~~c:実行結果
LINE : 5
FILE : test.c
DATE : Dec  1 2017
TIME : 00:00:00
~~~

## undef - マクロ定義削除

~~~c
#define COUNT      0x5
#undef  COUNT
~~~
## # - 文字列化演算子
マクロ引数をダブルクォーテーションを付けた文字列に変換する

~~~c
#include <stdio.h>

#define COUNTB    0x6
#define STRINGIFY1(x)    #x
#define STRINGIFY2(x)    STRINGIFY1(x)

int main()
{
    // 一段階のマクロでは引数xはマクロ展開されない
    printf(STRINGIFY1(COUNTB));
    
    // 引数xのマクロ展開を先に実施するために二段階のマクロを使用
    printf(STRINGIFY2(COUNTB));
}
~~~

~~~c:実行結果
COUNTB
0x06
~~~

## ## - 文字列連結演算子

~~~c
#include <stdio.h>

#define COUNTB    0x6
#define COMBINE_COUNT(x, y)    x ## y

int main()
{
    printf("%d\n", COMBINE_COUNT(COUNT, B));
}
~~~

~~~c:実行結果
6
~~~

## include - ファイルインクルード

~~~c
// 標準ヘッダファイルのインクルード
// 標準ヘッダファイル格納ディレクトリのみ探索
#include <stdio.h>

// 作成ヘッダファイルのインクルード
// カレントディレクトリ → 標準ヘッダファイル格納ディレクトリの順で探索
#include "aaa.h"
~~~

## if/else/elif/endif - 条件付きコンパイル

~~~c
#define MODELA   0x01

#if MODELA
    // モデルAの処理
#elif MODELB
    // モデルBの処理
#else
    // 他のモデルの処理
#endif
~~~

## ifdef/ifndef - 条件付きコンパイル

~~~c:定義があれば有効
#define MODELA   0x00

#ifdef
    // モデルAの処理
#endif
~~~
~~~c:多重インクルードガード
#ifndef HELLOWOLRD_H_
#define HELLOWOLRD_H_

#endif /* HELLOWOLRD_H_ */
~~~

## error - エラーメッセージ

~~~c
#define TABLE_ADDRESS   0x20000000

#if (TABLE_ADDRESS % 64) != 0
#error "ADDRESS ALIGNMENT ERROR"
#endif
~~~

# ■ 宣言
## 記憶クラス指定子
### auto
* 局所(自動)変数であることを指定
* 一般的には省略
* ブロック内変数のデフォルト記憶域クラス

~~~c
#include <stdio.h>

int main()
{
    auto int count = 0;
    printf("%d", count);
}
~~~

### static
* 関数、変数宣言時に使用
* 関数の場合、他のファイルからのコールが不可
* 変数の場合、静的変数であることを指定。他のファイルからのアクセスが不可

~~~c
#include <stdio.h>

static int countA = 0x01;

int main()
{
    static int countB = 0x02;
    printf("%d", countA);  // OK
    printf("%d", countB);  // OK
}

static void sub()          // 他のファイルからコール不可
{
    printf("%d", countA);  // OK
    printf("%d", countB);  // ビルドエラー
}
~~~

### register

* 仮引数または局所変数の宣言時に使用
* アクセス時間最適化のため、コンパイラへレジスタ割り付けのヒント情報を与える

~~~c
int sub(register int a, register int b)
{
    register int temp = 0;
  
    for(i = 0; i < 10; i++)
    {
        temp += a + b * i
    }

    return temp;
}
~~~

### extern

* 関数、変数宣言時に使用
* 外部ファイルで定義された関数、変数を参照する際に指定
* 参照側のファイルで定義

~~~c:main.c
#include <stdio.h>        

// 一般的にはextsub.hとして外部提供関数・変数を定義し、main.cからインクルードする
extern int count;
extern int sub();

int main()
{
    printf("%d\n", count);    // 10
    printf("%d\n", sub());    // 20
}
~~~

~~~c:sub.c
int count = 10;

int sub()
{
    return 20;
}
~~~

### typedef

* データ型に対して名前を定義

~~~c:stdint.h
typedef signed char        int8_t;
~~~

## 関数指定子

### inline

* 関数宣言時に使用
* コンパイラに当該関数のインライン展開を促すための通知
* 関数呼び出しのオーバーヘッド削減になるが、オブジェクトサイズが増加する場合がある

~~~c
inline int sub()
{
    return 20;
}
~~~

## 型修飾子

### const

* 変数宣言時に使用
* 当該変数が定数である場合に使用し、書き換えるとコンパイルエラーが発生する

~~~c
const int count = 100;
~~~