C言語 - 標準ライブラリ - time.h - struct timeval、struct timespec を使用する(秒単位以下)

 
1. gettimeofday, settimeofday 日付と時刻の取得 / 設定
2. nanosleep n(ナノ)秒単位でスリープ
3. timeradd, timersub, timercmp 日時計算

1. gettimeofday, settimeofday 日付と時刻の取得 / 設定


#include <sys/time.h>

int	gettimeofday(struct timeval *tp, struct timezone *tzp);
int	settimeofday(const struct timeval *tp, const struct timezone *tzp);
 当然、gettimeofday で取得、settimeofday で設定になります。  struct timeval 型は 以下の形式

struct timeval
{
	long    tv_sec;         // 1970 年 1月 1日からの秒数
	long    tv_usec;        // およびμ(マイクロ)秒数
};
 struct timezone 型は、タイムゾーンを表すもので、本来、夏時間を定義して日時を扱うためのものでしたが、コンピュータで扱うには不向き(政治的問題が大きくからむ)であることから廃止の方向ですので、明示的に NULL を引数にします。  そもそも、どっかの馬鹿の政治家くらいしか、夏時間なんてことは考えないのですよ。

2. nanosleep n(ナノ)秒単位でスリープ


#include <time.h>

int	nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
 基本は rqtp で指定した時間スリープします。  きっちり待ち時間分スリープした場合は、戻り値は 0 になります。  スリープ中にシグナルによって起動された場合、rmtp が NULL でなければ rmtp に残りの時間が設定されます。  このとき戻り値には -1 が設定され、error に EINTR が設定されます。  struct timespec 型は 以下の形式

struct timespec
{
    time_t tv_sec;        // 秒
    long   tv_nsec;       // n(ナノ)秒
};
 いささか汎用性に欠けるので、例えば、精度をミリ秒単位までとし、シグナルが発生しないものとすれば例えば

int myNanosleep(int second, int millisecond)
{
	struct timespec rqtp = {};
	struct timespec rmtp = {};

	rqtp.tv_sec  = second;
	rqtp.tv_nsec = millisecond * 1000 * 1000;

	return nanosleep(&rqtp, &rmtp);
}
 のような関数を書けば、秒単位・ミリ秒単位で実行を停止させることができます。

3. timeradd, timersub, timercmp 日時計算

 これは内容は関数でなくマクロらしいです。

#include <sys/time.h>

void timeradd(struct timeval *a, struct timeval *b, struct timeval *res);
void timersub(struct timeval *a, struct timeval *b, struct timeval *res);
int timercmp(struct timeval *a, struct timeval *b, CMP);
 timeradd は a と b を足した結果を res に返します。  timersub は a から b を引いた結果を res に返します。  timercmp は a と b を CMP に示す記号が真(0以外)か偽(0)かを返します。  CMP には「<」「>」「!=」のいずれかを使います。  「>=」や「==」もコンパイルエラーにはなりませんが、コンパイラによって結果が異なることがあるらしい。  下記のソースを書いて
#include <limits.h>
#include <stdio.h>
#include <sys/time.h>

static void timerset(struct timeval* c, time_t* time_c);

int main(int argc, char* argv[])
{
	for (int i=0; i<5; i++)
	{
		struct timeval c = {};
		time_t time_c = 0;

		timerset(&c, &time_c);

		printf("前回との時刻差は[%02ld]秒です\n", time_c);
		printf("前回との時刻差は[%02ld.%06ld]秒です\n", c.tv_sec, c.tv_usec);
		printf("\n");
	}

	return 0;
}

void timerset(struct timeval* c, time_t* time_c)
{
	static unsigned char virgin = 1;

	static struct timeval a = {};
	struct timeval b = {};

	static time_t time_a = 0;
	time_t time_b = 0;

	if (virgin != 0)
	{
		gettimeofday(&a, NULL);
		time_a = time(NULL);
		virgin = 0;
		return;
	}

	gettimeofday(&b, NULL);
	time_b = time(NULL);

	*time_c = time_b - time_a;
	time_a = time_b;

	timersub(&b, &a, c);
	a = b;
}

 実行すると下記の結果が得られます。
前回との時刻差は[00]秒です
前回との時刻差は[00.000000]秒です

前回との時刻差は[00]秒です
前回との時刻差は[00.000037]秒です

前回との時刻差は[00]秒です
前回との時刻差は[00.000002]秒です

前回との時刻差は[00]秒です
前回との時刻差は[00.000001]秒です

前回との時刻差は[00]秒です
前回との時刻差は[00.000001]秒です

 当たり前のことですが time では得られない差を gettimeofday で得ることができるわけです。