static関数

Copyright(C) 14May2003 coskx

複数のファイルからなる大規模プログラミングでは,一連の関数群を1つのファイルに作りこみ,いくつかのプログラムでその関数群を再利用することが多い。一連の関数群のうち,他のファイルから呼び出されない関数は,そのままでは関数名が重複してしまうことがあり,好ましくない。他のファイルから呼び出されない関数は関数名をそのファイル内でのみ有効にして,ほかのファイルからは見えないようにすることができる。

マルチソースファイル中で,関数にstatic修飾をつけると,その関数は,他のソースファイルからみえなくなる。この機能を用いると関数名の衝突事故を防ぐことが出来る。

1.static宣言された関数の利用例


あるソースファイル「〜.c」で定義している関数のうち,公開する関数はヘッダファイル「〜.h」にプロトタイプ宣言を記述し,公開しない関数はstatic修飾をつける。static宣言された関数名は,そのファイル中でのみ有効になる。このようにすると関数名の衝突を防ぐことが出来る。

もともと「static」は静的の意味であるが,ここでは「local」の意味と解釈した方がよい。

次の例は時間構造体の演算関数群を定義しているソースファイル中で,公開する関数はヘッダファイル「〜.h」にプロトタイプ宣言を記述し,公開しない関数はstatic修飾をつけている。

TOmain.c

#include <stdio.h>
#include "timeOperation.h"

int main()
{
    hmstime_t t1,t2,t3;
    double k=2.0,ratio;
    char tstr1[32],tstr2[32],tstr3[32];
    t1=StrtoTime("2:26:48");
    t2=StrtoTime("2:34:50");
    TimeToStr(tstr1,t1);
    TimeToStr(tstr2,t2);

    t3=addTime(t1,t2);
    TimeToStr(tstr3,t3);
    printf("%s+%s=%s\n",tstr1,tstr2,tstr3);

    t3=subtractTime(t1,t2);
    TimeToStr(tstr3,t3);
    printf("%s-%s=%s\n",tstr1,tstr2,tstr3);

    t3=subtractTime(t2,t1);
    TimeToStr(tstr3,t3);
    printf("%s-%s=%s\n",tstr2,tstr1,tstr3);

    t3=multiplyTime(t1,k);
    TimeToStr(tstr3,t3);
    printf("%s*%f=%s\n",tstr1,k,tstr3);

    t3=divideTime(t1,k);
    TimeToStr(tstr3,t3);
    printf("%s/%f=%s\n",tstr1,k,tstr3);

    ratio=divideTime2(t1,t2);
    printf("%s/%s=%f\n",tstr1,tstr2,ratio);

    ratio=divideTime2(t2,t1);
    printf("%s/%s=%f\n",tstr2,tstr1,ratio);
    return 0;
}

timeOperation.h

/*---------------------------------------------
時間の演算を定義する関数群
時間に関する演算として次のものを定義する。
時間+時間→時間
時間-時間→時間
時間*定数→時間
時間/定数→時間
時間/時間→定数
---------------------------------------------*/
typedef struct {
    int sign;   /*1 or -1*/
    int hour;   /*時間*/
    int min;    /*分*/
    double sec; /*秒*/
} hmstime_t;

hmstime_t addTime(hmstime_t t1, hmstime_t t2);         /*時間+時間→時間*/
hmstime_t subtractTime(hmstime_t t1, hmstime_t t2);    /*時間-時間→時間*/
hmstime_t multiplyTime(hmstime_t t1, double k);        /*時間*定数→時間*/
hmstime_t divideTime(hmstime_t t1, double k);          /*時間/定数→時間*/
double divideTime2(hmstime_t t1, hmstime_t t2);        /*時間/時間→定数*/
hmstime_t StrtoTime(char *str);                   /*文字列hh:mm:ss→時間*/
void TimeToStr(char *str,hmstime_t t);            /*時間→文字列hh:mm:ss*/

timeOperation.c

#include <stdio.h>
#include "timeOperation.h"

static hmstime_t normalizeTime(hmstime_t t)
{
    int tmp;
    double subsec;
    if (t.sign!=-1) t.sign=1;
    tmp=(int)t.sec;
    subsec=t.sec-tmp;
    t.sec=tmp%60+subsec;
    tmp/=60;
    t.min+=tmp;
    tmp=t.min/60;
    t.min%=60;
    t.hour+=tmp;
    return t;
}

static double convertTimetoDouble(hmstime_t t)
{
    double x;
    x=t.sec+60.0*t.min+3600.0*t.hour;
    if (t.sign==-1) x=-x;
    return x;
}

static hmstime_t convertDoubletoTime(double x)
{
    hmstime_t time={1,0,0,0};
    double subsec;
    int tmp;
    if (x<0) {
        time.sign=-1;
        x=-x;
    }
    tmp=(int)x;
    subsec=x-tmp;
    time.sec=tmp%60+subsec;
    tmp/=60;
    time.min=tmp%60;
    time.hour=tmp/60;
    return time;
}

hmstime_t addTime(hmstime_t t1, hmstime_t t2)       /*時間+時間→時間*/
{
    double x1,x2;
    x1=convertTimetoDouble(t1);
    x2=convertTimetoDouble(t2);
    return convertDoubletoTime(x1+x2);
}

hmstime_t subtractTime(hmstime_t t1, hmstime_t t2)  /*時間-時間→時間*/
{
    double x1,x2;
    x1=convertTimetoDouble(t1);
    x2=convertTimetoDouble(t2);
    return convertDoubletoTime(x1-x2);
}

hmstime_t multiplyTime(hmstime_t t1, double k)      /*時間*定数→時間*/
{
    double x;
    x=convertTimetoDouble(t1);
    return convertDoubletoTime(x*k);
}

hmstime_t divideTime(hmstime_t t1, double k)        /*時間/定数→時間*/
{
    double x;
    x=convertTimetoDouble(t1);
    return convertDoubletoTime(x/k);
}

double divideTime2(hmstime_t t1, hmstime_t t2)      /*時間/時間→定数*/
{
    double x1,x2;
    x1=convertTimetoDouble(t1);
    x2=convertTimetoDouble(t2);
    return x1/x2;
}

hmstime_t StrtoTime(char *str)                  /*文字列hh:mm:ss→時間*/
{
    hmstime_t time={1,0,0,0};
    sscanf(str,"%d:%d:%lf",&time.hour,&time.min,&time.sec);
    if (time.hour<0) {
        time.sign=-1;
        time.hour=-time.hour;
    }
    return normalizeTime(time);
}

void TimeToStr(char *str,hmstime_t t)          /*時間→文字列hh:mm:ss*/
{
    char *format[2]={
        "%02d:%02d:%05.2f",
        "-%02d:%02d:%05.2f"
    };
    t=normalizeTime(t);
    sprintf(str,format[t.sign==-1],t.hour,t.min,t.sec);
}

実行結果
02:26:48.00+02:34:50.00=05:01:38.00
02:26:48.00-02:34:50.00=-00:08:02.00
02:34:50.00-02:26:48.00=00:08:02.00
02:26:48.00*2.000000=04:53:36.00
02:26:48.00/2.000000=01:13:24.00
02:26:48.00/02:34:50.00=0.948116
02:34:50.00/02:26:48.00=1.054723

2.複数ファイルのプログラミングの一般的な形

一般的には次のようなファイル構成となる。
「〜.h」には,元になる「〜.c」に定義されている関数のプロトタイプ宣言が書いてあり,関数が使われる「〜〜.c」にインクルードされるように使われる。なお,例えばsub3.cに定義されている関数がsub2.cで使われるなら,sub2.cにsub3.hをインクルードする必要がある。
sub1.c,sub2.c,sub3.c内にstaticとされた関数があるが,それらは定義されたファイル中でのみ有効な関数である。
たとえば「staic int localfunc1(...)」などは定義されたファイル(sub1.c)中のみ有効な関数となる。それゆえ,sub1.c,sub2.c,sub3.c内に同じ名前のstatic関数があってもかまわない。

main()を含むソース sub1.c sub2.c sub3.c

#include <...>
#include "sub1.h"
#include "sub2.h"
#include "sub3.h"

int funcm1(...)
{
    :
}

int funcm2(....)
{
    :
}

    :

int main()
{
    :
}

#include <...>
#include "sub1.h"

static int var1;
static double var2;

staic int localfunc1(...)
{
    :
}

staic int localfunc1(...)
{
    :
}

int func11(...)
{
    :
}

int func12(....)
{
    :
}

    :

#include <...>
#include "sub2.h"

static char buff[128];
static int var1;

staic int localfunc1(...)
{
    :
}

staic int localfunc2(...)
{
    :
}

int func21(...)
{
    :
}

int func22(....)
{
    :
}


    :
#include <...>
#include "sub3.h"

static int var1;

staic int localfunc1(...)
{
    :
}

staic int localfunc2(...)
{
    :
}

int func31(...)
{
    :
}

int func32(....)
{
    :
}


    :
  sub1.h sub2.h sub3.h
  int func11(...);
int func12(...);
    :
int func21(...);
int func22(...);
    :
int func31(...);
int func32(...);
    :