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

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

1. 概要

 ここでは、「time」や「localtime_r」で取得する時刻より精度の高い時刻の取得や、日時計算のメモをしています。

2. 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」を引数にします。  そもそも、どっかの馬鹿の政治家くらいしか、夏時間なんてことは考えないのですよ。

4. 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;
}

 実行すると下記の結果が得られます。
sh: /home/kitayama/lang/cpp/time/timersub: not found
 当たり前のことですが、「time」では得られない差を「gettimeofday」で得ることができるわけです。
earthcar(アースカー)