
■1.間違った理解・正しい理解
●間違った理解
マジックナンバーとは裸の数字の事である。
マクロは裸の数字ではないので
マジックナンバーではない。
●正しい理解
マジックナンバーとは意味のわからない数字の事である。
■2.無理に0をマクロにした例
#define ZERO 0U
#define ONE 1U
#define TWO 2U
#define THREE 3U
#define TOP_OF_ARY 0 //配列の先頭添え字
#define MY_PROJECT_ZERO 0 //自プロジェクト用ゼロ
int f(void) {
//自動変数の初期化
int x = MY_PROJECT_ZERO ;
int y = MY_PROJECT_ZERO ;
int z = MY_PROJECT_ZERO ;
char ary[] = "string";
for(char *p = &ary[TOP_OF_ARY]; *p != ZERO ; p += ONE){
printf("%c\n",p[ZERO]);
}
//長い処理
return x+y+z;
}
0は小学生でも知っている数字なので
べたで0と記述した方がわかりやすいです。
逆に、
余計なマクロを定義して変数初期化等で多用すると
コードが非常に読みにくくなります。
つまり
#define MY_PROJECT_ZERO 0
int x = MY_PROJECT_ZERO ;
より
int x = 0 ;
のほうが読みやすいです。
■3.0と書いたほうがわかりやすい例
int g(void) {
//自動変数の初期化
int x = 0 ;
int y = 0 ;
int z = 0 ;
char ary[] = "string";
for(char *p = &ary[0]; *p != '\0'; p++){
printf("%c\n",p[0]);
}
//長い処理
return x+y+z;
}
こう書いてください
■4.マジックナンバー禁止と言われて
#define ICHI 1
#define NI 2
#define SAN 3
double 三角形の面積(double 底辺,double 高さ){
return (底辺 * 高さ)/ NI ;
}
マクロでNIと書くと
かえって何だかわからなくなるので、
べたで2と書いてください
■5.文脈から自明な定数をマクロにする必要はない
#define _0x000000FF 0xFF
#define _0x0000FF00 0xFF00
#define _0x00FF0000 0xFF0000
#define _0xFF000000 0xFF000000
#define SHIFT_eight 8
#define SHIFT_sixteen 16
#define SHIFT_twenty_four 24
uint32_t swap32NG(uint32_t value) {
uint32_t ret;
ret = (value & _0x000000FF) << SHIFT_twenty_four;
ret |= (value & _0x0000FF00) << SHIFT_eight;
ret |= (value & _0x00FF0000) >> SHIFT_eight;
ret |= (value & _0xFF000000) >> SHIFT_twenty_four;
return ret;
}
文脈から自明な定数を
無理にマクロにすると却ってわかりにくくなります。
■6.16進数で書いたほうがわかりやすい例
uint32_t swap32OK(uint32_t value) {
uint32_t ret;
ret = (value & 0x000000FF) << 24;
ret |= (value & 0x0000FF00) << 8;
ret |= (value & 0x00FF0000) >> 8;
ret |= (value & 0xFF000000) >> 24;
return ret;
}
やかましい静的解析ツールはこのコードに対して
マジックナンバーを使ったと文句を言うかもしれません。
そういう時は静的解析ツールのサポートセンターに
どう書くべきか質問しましょう。
併せて下記参考の DCL06-EX1 の対処方法も
サポートセンターに質問すると良いでしょう。
参考:
DCL06-EX1: 数値定数をシンボル定数に置き換えることは多くの場合よいプラクティスであるが、やりすぎになる場合もある。
https://www.jpcert.or.jp/sc-rules/c-dcl06-c.html