MA-SATANのエンジニアブログ

とある大阪の日本酒Loveなエンジニアの開発ブログ

C言語 constを外してみる

当たり前ですが、constで定義した値を書き換えるようなことをしてはいけません。
constの復習と無理やり書き換えようとした場合の動作を確認してみます。

constのパターン

constの使い方として3パターンあります。

1. 定数データ

ポインタが指しているデータを定数にします。
データは変更不可だが、ポインタは変更可能。

int main(int argc, char* argv[])
{
    const char* value_01 = "neogeo";   /* 定数データ */
    const char* value_02 = "genesis";

    value_01[0] = 'x';        /* コンパイルエラー */
    value_01    = value_02;   /* セーフ */
    return 0;
}

=== コンパイル結果 ===
エラー: 読み取り専用位置 ‘*value_01’ への代入です
2. 定数ポインタ(その1)

ポインタを定数にします。
 ポインタは変更不可だが、データは変更可能。
 ※ただし、ポインタが指すデータが読み取り専用であれば、データの変更は不可です。

int main(int argc, char* argv[])
{
    char data[]          = "nes";
    char* const value_01 = data;   /* 定数ポインタ */

    value_01[0] = 'x';             /* セーフ */
    value_01    = data;            /* コンパイルエラー */

    printf("value_01=%s\n", value_01);
    return 0;
}

=== コンパイル結果 ===
エラー: 読み取り専用変数 ‘value_01’ への代入です
3. 定数データ&定数ポインタ

データもポインタも定数になります。

int main(int argc, char* argv[])
{
    const char* const value_01 = "vita";     /* 定数データ&定数ポインタ */
    char* value_02             = NULL;

    value_01[0] = 'x';     /* コンパイルエラー */
    value_01 = value_02;   /* コンパイルエラー */
    return 0;
}

=== コンパイル結果 ===
エラー: 読み取り専用位置 ‘*value_01’ への代入です
エラー: 読み取り専用変数 ‘value_01’ への代入です
4. constを外してキャストしてみる

定数データを通常のcharへキャストして、データを変更してみます。
結果はコンパイルは通りますが、変更するデータが読み取り専用位置にあるデータであればセグメンテーションエラーが発生します。
value_02のようにスタックに配置されてるデータであれば、変更は可能です。

int main(int argc, char* argv[])
{
    const char* data01  = "hello";     /* 定数データ   */
    char data02[]       = "good bye";  /* 通常のデータ */

    /* 定数ポインタ */
    const char* value_01 = data01;
    const char* value_02 = (const char*)data02;

    /* これはコンパイルエラー
    value_01[0] = 'x';
    value_02[0] = 'y';
    */

    /* constを外してキャストする */
    char* value_03 = (char*)value_01;
    char* value_04 = (char*)value_02;

    value_03[0] = 'x';    /* データ変更 NG 実行時エラー */
    value_04[0] = 'y';    /* データ変更 OK */

    printf("value_01=%s\n", value_01);
    printf("value_02=%s\n", value_02);

    return 0;
}