staticとconst

staticについては Practical Programming in C - Lec01 で少しだけ書いたけど、おさらいしてみる。

static宣言

使い方は2通り。1つは外部変数や関数のスコープをそのファイルのみに閉じること。もう1つは関数の内部変数に適用し、静的領域にメモリを確保すること。*1

外部変数や関数への適用

まずは関数への適用例を示す。

static.h
static int square(int n);
static.c
static int square(int n)
{
    return n * n;
}
main.c
#include "static.h"

int main(void)
{
    square(100);
    return 0;
}

これらをコンパイルするとエラーになるので、確かに関数のスコープを限定できてることがわかる。

$ gcc static.c main.c 
static.h:2: warning: ‘square’ used but never defined

次に外部変数への適用例を示す。

file1.c
int i = 1;
file2.c
int i = 2;
int main(void)
{
    return 0;
}

これらをコンパイルするとエラーになる。

$ gcc file1.c file2.c 
duplicate symbol _i in:

ここでfile1.cを

static int i = 1;

とすることで、コンパイルエラーが出なくなるので、static宣言によってスコープが限定されたことが分かる。

内部変数への適用

内部変数は通常スタック領域にメモリ確保されるが、static宣言をすると静的領域にメモリ確保される。

staticval.c
#include <stdio.h>

void test(void)
{
    int n = 0;
    n++; 
    printf("%d\n", n);
    printf("%p\n", &n);
}

void test_static(void)
{
    static int n = 0;
    n++; 
    printf("%d\n", n);
    printf("%p\n", &n);
}

int main(void)
{
    test(); // 1
    test(); // 1

    test_static(); // 1
    test_static(); // 2
}

これを実行すると...

$ gcc staticval.c && ./a.out  
1
0x7fff55805fbc
1
0x7fff55805fbc
1
0x10a3fa068
2
0x10a3fa068

となる。

f:id:kotaroito2002:20140409233610j:plain

出典: http://www.andrew.cmu.edu/course/15-412

上図の通り、static宣言した変数は下位アドレスにメモリ確保されていることも分かる。

const宣言

staticとは何が違うのか? staticはメモリに関する話であり、必ずしも定数とは限らない。const宣言は定数であることを保証してくれる。

カンタンな例で言うと下記ケースはコンパイルエラーになる。

int main(void)
{
    const int i = 1;

    i++; // コンパイルエラー
    return 0;
}

また、関数の仮引数に変更を加えないことを保証できる。

void test(const char str[])
{
    char[0] = 's'; // コンパイルエラー
}

int main(void)
{
    char str[] = "test";
    test(str);

    return 0;
}

*1:C言語的には正確でない説明かもしれない..