C言語 | 構造体の宣言 | 型修飾子 - const

この記事では、変更できない値に使う const 型修飾子と、最適化で省略してはならない値に使う volatile 型修飾子を説明する。

読み取り専用の値

宣言には、記憶域クラス指定子、型指定子、型修飾子、宣言子、初期化子を含められる。

記憶域クラス指定子 型指定子 型修飾子 宣言子 初期化子 ...;

最もよく使われる型修飾子は const である。初期化後に値を変更できないことを表す。

const int ciValue = n;

アプリケーション名やバージョンのように共有する値は、プログラム内でリテラルを繰り返さず、一度だけ宣言するとよい。const は意図しない変更から値を保護する。

コード1

#include <stdio.h>

typedef unsigned char BYTE;
const char APPNAME[] = "Kitty on your lap";
const int VERSION = (15 << 8) | 7;

int main() {
 /* APPNAME[1] = 'X'; */ /* error */
 /* VERSION = 0; */      /* error */
 printf("APPNAME = %s\n" , APPNAME);
 printf("VERSION = %d.%d\n" , (BYTE)VERSION , (BYTE)(VERSION >> 8));
 return 0;
}

配列を const で修飾すると、すべての要素が読み取り専用になる。

ポインターでは const の位置が重要である。読み取り専用データへのポインターは参照先の値を変更できないが、別のアドレスを指すことはできる。

const char *str = buf1;
/* *str = 'a'; */ /* error */
str = buf2;       /* OK */

定数ポインターは別のアドレスを指せないが、参照先の値は変更できる。

char *const str = buf1;
*str = 'a';       /* OK */
/* str = buf2; */ /* error */

コード2

#include <stdio.h>

void Function(const char *str) {
 /* str[0] = 'X'; */ /* error */
 printf("%s\n" , str);
}

int main() {
 Function("Kitty on your lap");
 return 0;
}

最適化の抑制

volatile 型修飾子は、ハードウェアや別の権限を持つプロセスなど、現在のプログラム以外から値が変更される可能性をコンパイラーへ伝える。

volatile int viValue = n;

コンパイラーは以前の値がそのまま有効だと仮定せず、必要なときにvolatile値を読み取る。

コード3

#include <stdio.h>

volatile int viVariable = 0xFF;
const volatile char *str = "Kitty on your lap";

int main() {
 printf("viVariable = %d\nstr = %s\n" , viVariable , str);
 return 0;
}

constvolatile は同時に指定できる。この場合、現在のプログラムは値を変更できないが、外部から変更される可能性はある。