きっかけ
業務として初めてC89(C90)のC言語環境に飛び込むことになった。(組み込み関係)
良く知らない環境なのでお勉強しようと思った。
とはいえ大体は参考のリンク先で分かるので、その他気が付いたことを書く。
参考
C言語の最新事情を知る: C99の仕様 - Build Insider
Diagnostic flags in Clang — Clang 6 documentation
↑記事を書いてから気が付いたけど、コンパイラが言語規格に準拠している前提であれば警告を見れば規格のエッセンスが分かりそうだ。
動作確認環境
環境はWandbox使ってみた: [Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ
※この記事では、clang5.0.0使ってOptimizationにチェックして-std=c89
にして-Weverything
付けた環境で見てみた
設定例:https://wandbox.org/permlink/IauhP7p8oMNB6kFy
変数の宣言時初期化
変数宣言はスコープの先頭だけでしょ、宣言は処理の前に書かないとダメなんでしょ。知ってる知ってる。
と思っていたけど、変数宣言時の初期化であれば関数呼び出しも書ける。
ということはC89であっても下記のリファクタリングができる。
before
#include <stdio.h>
static int func(void) {
return 0;
}
int main(void) {
int val;
val = func();
printf("val = %d\n", val);
return 0;
}
after
#include <stdio.h>
static int func(void) {
return 0;
}
int main(void) {
const int val = func(); /* 宣言時に初期化! */
printf("val = %d\n", val);
return 0;
}
before_例2
#include <stdio.h>
static int func(void) {
return 0;
}
static int func2(int i) {
return i + 1;
}
int main(void) {
int val;
int val2;
val = func();
val2 = func2(val);
printf("val = %d\n", val);
printf("val2 = %d\n", val2);
return 0;
}
after_例2
#include <stdio.h>
static int func(void) {
return 0;
}
static int func2(int i) {
return i + 1;
}
int main(void) {
const int val = func(); /* 宣言時に初期化! */
const int val2 = func2(val); /* 宣言時に初期化した変数を使って宣言時に初期化! */
printf("val = %d\n", val);
printf("val2 = %d\n", val2);
return 0;
}
構造体の宣言時初期化とコンパイル時定数
構造体の初期化周りはコンパイル時定数でなくてはならないという制限がC89にはある。
つまり、下記のようなリファクタリングはC89だと無理(C99やC++03であれば可能)。
before
#include <stdio.h>
typedef struct ST {
int x;
}ST;
static int func(void) {
return 0;
}
int main(void) {
const int val = func();
ST st;
st.x = val;
printf("val = %d\n", val);
printf("st.x = %d\n", st.x);
return 0;
}
after(error!)
#include <stdio.h>
typedef struct ST {
int x;
}ST;
static int func(void) {
return 0;
}
int main(void) {
const int val = func();
const ST st = {val}; /* error: initializer for aggregate is not a compile-time constant */
printf("val = %d\n", val);
printf("st.x = %d\n", st.x);
return 0;
}