最終的にはtypedefのtime_tは何ですか?


回答:


175

ウィキペディアtime_t記事の記事は、これに光を当てています。つまりtime_t、C仕様ではのタイプは保証されていません。

time_tデータ型はシステム時間値を格納するために定義されたISO Cライブラリ内のデータ・タイプです。このような値は、標準time() ライブラリ関数から返されます。このタイプは、標準ヘッダーで定義されているtypedefです。ISO Cでは、time_tを算術型として定義していますが、特定の型、範囲、解像度、またはエンコーディングを指定していません。また、時間値に適用される算術演算の意味も規定されていません。

UnixおよびPOSIX準拠のシステムは、time_tタイプをsigned integer(通常32ビットまたは64ビット幅)として実装します。これは、Unixエポックの開始以降の秒数を表します。負の時間値を正しく処理できるシステムもあれば、そうでないシステムもあります。32ビットtime_tタイプを使用するシステムは、2038年問題の影響を受けます


6
ただし、time_t値は通常、ディスクではなくメモリにのみ格納されることに注意してください。代わりに、time_tはテキストまたは他のポータブルフォーマットに変換されて永続的に保存されます。そのため、Y2038の問題は実際には問題になりません。

11
@Heath:同じ人がオペレーティングシステムとCライブラリを作成する特定のシステムでは、time_tディスク上のデータ構造での使用が発生する可能性があります。ただし、ファイルシステムは他のオペレーティングシステムによって読み取られることが多いため、このような実装に依存するタイプに基づいてファイルシステムを定義することは愚かなことです。たとえば、32ビットシステムと64ビットシステムの両方で同じファイルシステムが使用され、time_tサイズが変更される場合があります。したがって、ファイルシステムは、より厳密に定義する必要があります(「1970年の開始からの秒数を表す32ビットの符号付き整数、UTCで」)time_t

1
注:リンクされているWikipediaの記事は削除され、time.hコンテンツのリストにリダイレクトされるようになりました。その記事のcppreference.comへのリンクが、コンテンツがどこにも見つからないです引用...
のMichałGórny

3
@MichałGórny:修正されました。記事が削除されない限り、常に正しいバージョンを見つけるために履歴を見ることができます。
Zeta

4
-1; Wikipediaから引用された、POSIX time_tが署名済みであることを保証しているという主張は誤りです。pubs.opengroup.org/onlinepubs/9699919799/basedefs/…は、さまざまなものが「符号付き整数型」または「符号なし整数型」でなければならないことを示していますが、「整数型でなければならない」time_tとだけ述べています。実装により、署名なしにしても、POSIXに準拠できます。time_t
Mark Amery

112

[root]# cat time.c

#include <time.h>

int main(int argc, char** argv)
{
        time_t test;
        return 0;
}

[root]# gcc -E time.c | grep __time_t

typedef long int __time_t;

それは$INCDIR/bits/types.hを通して定義されます:

# 131 "/usr/include/bits/types.h" 3 4
# 1 "/usr/include/bits/typesizes.h" 1 3 4
# 132 "/usr/include/bits/types.h" 2 3 4

1
私は両方の参照typedef __int32_t __time_t;typedef __time_t time_t;FreeBSD freebsd-test 8.2-RELEASE-p2 FreeBSD 8.2-RELEASE-p2 #8: Sun Aug 7 18:23:48 UTC 2011 root@freebsd-test:/usr/obj/usr/src/sys/MYXEN i386。結果はLinuxのように明示的に設定されます(少なくともDebianの2.6.32-5-xen-amd64)。
ssice

1
@Vietは、ファイルを作成せずにワンライナーでも可能です:stackoverflow.com/a/36096104/895245
Ciro Santilli郝海东冠状病六四事件法轮功

1
なぜgrepを使用して、基になるタイプを見つけ__time_tないtime_ttime_tですか?ステップを省略しますか?
chux-モニカの復活

@ chux-ReinstateMonica-OPは、time_tから__time_tまでのtypedefを見つけたと述べました。この回答は、__ time_tが何として定義されているかという質問に対処するだけです。しかし、一般的なケース(time_tが__time_tに型指定されない場合がある)では、最初にtime_tに対してgrepを実行し、次に、返される結果に対して再度grepを実行する必要があることに同意します
Michael Firth

@MichaelFirth公正です。OPがを見つけたとしても、typedef __time_t time_t;typedefが実際に使用され、条件付きコンパイルの一部だけではないことを確認するために、周囲のコードの検査も必要であることを思い出しました。 typedef long time_t;も発見された可能性があります。
chux-モニカを

30

規格

ウィリアム・ブレンデルはウィキペディアを引用したが、私は馬の口からそれを好む。

C99 N1256標準ドラフト 7.23.1 / 3「時間の構成要素」は次のように述べています。

宣言されたタイプは、size_t(7.17で説明)clock_tおよびtime_tであり、時間を表すことができる算術タイプです。

および6.2.5 / 18「タイプ」と言います。

整数型と浮動小数点型はまとめて算術型と呼ばれます。

POSIX 7 sys_types.hは言う:

[CX] time_tは整数型でなければなりません。

どこ[CX]されるように定義

[CX] ISO C標準への拡張。

これは、より強力な保証を行うための拡張です。浮動小数点は除外されます。

gccワンライナー

Quassnoiで言及されているファイルを作成する必要はありません。

echo | gcc -E -xc -include 'time.h' - | grep time_t

Ubuntu 15.10 GCC 5.2では、上の2行は次のとおりです。

typedef long int __time_t;
typedef __time_t time_t;

からの引用付きのコマンドの内訳man gcc

  • -E:「前処理の後で停止します。適切なコンパイラを実行しないでください。」
  • -xc:入力はファイル拡張子のないstdinから来るため、C言語を指定します。
  • -include file: "" #include "file" "がプライマリソースファイルの最初の行にあるかのようにファイルを処理します。"
  • -:stdinからの入力

1
エコーからのパイプも不要ですgcc -E -xc -include time.h /dev/null | grep time_t
。– rvighne

12

答えは間違いなく実装固有です。ご使用のプラットフォーム/コンパイラーを明確に見つけるには、コードのどこかにこの出力を追加します。

printf ("sizeof time_t is: %d\n", sizeof(time_t));

答えが4(32ビット)であり、データが2038を超えることを意図している場合、コードの移行には25年の余裕があります。

データが文字列として保存されていれば、次のような単純なデータであっても、データは問題ありません。

FILE *stream = [stream file pointer that you've opened correctly];
fprintf (stream, "%d\n", (int)time_t);

次に、それを同じ方法で読み戻し(fread、fscanfなどをintに)、エポックオフセット時間を取得します。同様の回避策が.Netにも存在します。WinシステムとLinuxシステムの間で64ビットのエポック番号を(通信チャネルを介して)問題なく渡します。これはバイト順の問題を引き起こしますが、それは別の問題です。

paxdiabloの質問に答えるには、プログラムが次のように記述されているため、「19100」と表示されたと思います(80年代に自分で作成したことは認めます)。

time_t now;
struct tm local_date_time;
now = time(NULL);
// convert, then copy internal object to our object
memcpy (&local_date_time, localtime(&now), sizeof(local_date_time));
printf ("Year is: 19%02d\n", local_date_time.tm_year);

このprintfステートメントは、固定文字列 "Year is:19"を出力し、その後に "1900年からの年数"をゼロで埋めた文字列を出力します(の定義tm->tm_year)。2000年には、その値は明らかに100です。"%02d"2つのゼロが埋め込まれますが、2桁より長い場合は切り捨てられません。

正しい方法は次のとおりです(最後の行にのみ変更):

printf ("Year is: %d\n", local_date_time.tm_year + 1900);

新しい質問:その考えの根拠は何ですか?


2
あなたは、おそらく使用すべき%zuフォーマットに書式指定子をsize_t(によって得られたような値sizeof)は、符号なしているとして(、 u()と長さsize_t型のz・)
アドリアン・ギュンター

...または問題を使用printf ("sizeof time_t is: %d\n", (int) sizeof(time_t));して回避しzます。
chux-モニカを

6

Visual Studio 2008では、__int64を定義しない限り、デフォルトでに設定されます_USE_32BIT_TIME_T。それがどのように定義されているのかがわからないふりをする方がよいでしょう。


2
これは通常は機能しますが、プログラムが30年後に発生することを追跡することを目的としている場合、署名された32ビットのtime_t がないことが非常に重要です。
ロブ・ケネディ

4
@ロブ、バ、任せろ!Y2Kの場合と同じように、2036年にはヘッドレスチキンのように走り始めます。私たちの何人かはY2k38コンサルタントであることから大量のお金を稼ぐでしょう、レナード・ニモイは私たちがすべて森に行って隠れるべきかについての別の陽気な本を持ち出します...
paxdiablo

1
...そして、それはすべて吹き飛ばされ、一般大衆はすべての大騒ぎが何であったか疑問に思いました。子供たちの遺産のためにいくらかお金を稼ぐために引退から出てくるかもしれません:-)。
paxdiablo 2009年

2
ところで、Y2Kバグは1つしか見つかりませんでした。これは日付を19100年1月1日と記載したWebページでした。理由について読者に確認してください...
paxdiablo

9
30年後に発生するイベントが「このバックアップの期限切れ」である場合、2038年ではなく、今問題が発生している可能性があります。今日の32ビットtime_tに30年を追加すると、過去の日付が取得されます。プログラムは処理するイベントを探し、(100年までに)期限切れのイベントを見つけて実行します。エラーが発生しました。バックアップはありません。
ロブ・ケネディ

5

time_tlong int64ビットマシンのタイプですlong long int。それ以外の場合はです。

これらのヘッダーファイルでこれを確認できます。

time.h/usr/include
types.htypesizes.h/usr/include/x86_64-linux-gnu/bits

(以下のステートメントは1つずつではありません。それらはCtrl + f検索を使用してそれぞれのヘッダーファイルで見つけることができます。)

1) time.h

typedef __time_t time_t;

2) types.h

# define __STD_TYPE     typedef  
__STD_TYPE __TIME_T_TYPE __time_t;  

3) typesizes.h

#define __TIME_T_TYPE       __SYSCALL_SLONG_TYPE  
#if defined __x86_64__ && defined __ILP32__  
# define __SYSCALL_SLONG_TYPE   __SQUAD_TYPE  
#else
# define __SYSCALL_SLONG_TYPE   __SLONGWORD_TYPE
#endif  

4)再び types.h

#define __SLONGWORD_TYPE    long int
#if __WORDSIZE == 32
# define __SQUAD_TYPE       __quad_t
#elif __WORDSIZE == 64
# define __SQUAD_TYPE       long int  

#if __WORDSIZE == 64
typedef long int __quad_t;  
#else
__extension__ typedef long long int __quad_t;

これらのファイルは、Ubuntu 15.10 BTW上のglibcによって提供されます。
Ciro Santilli郝海东冠状病六四事件法轮功

3
long intどこにでもあるわけではありません。stackoverflow.com/questions/384502/…を
Zan Lynx

4

これは、ほとんどのレガシープラットフォームでは32ビットの符号付き整数型です。ただし、これによりコードは2038年のバグに悩まされます。したがって、最新のCライブラリでは、署名された64ビットintとして定義する必要があります。これは、数十億年間安全です。



1

最終的にはtime_t typedefとは何ですか?

堅牢なコードはタイプが何であるかを気にしません。

C種はtime_tあることを実数型のようなdouble, long long, int64_t, int、など

unsignedエラーを示す多くの時間関数からの戻り値である可能性もありますが-1(time_t)(-1)-この実装の選択は一般的ではありません。

ポイントは、「知る必要がある」タイプがまれであることです。コードは必要性を避けるために書かれるべきです。


しかし、一般的な「知る必要がある」ことは、コードがrawを出力したいときに発生しますtime_t。最も広い整数型にキャストすると、最新のほとんどのケースに対応できます。

time_t now = 0;
time(&now);
printf("%jd", (intmax_t) now);
// or 
printf("%lld", (long long) now);

doubleまたはへのキャストlong doubleも機能しますが、不正確な 10進数出力を提供する可能性があります

printf("%.16e", (double) now);

ARMシステムからAMD64システムに時間を転送する必要があるので、状況を知る必要があります。time_tは、armでは32ビット、サーバーでは64ビットです。時間をフォーマットに変換して文字列を送信すると、非効率的で遅くなります。したがって、time_t全体を送信してサーバー側で整理する方がはるかに優れています。ただし、システム間でエンディアンが異なるために数値が複雑になりたくないため、タイプについてもう少し理解する必要があります。そのため、htonlを使用する必要があります...基になるタイプを見つけるために;)
フクロウ

もう1つの「知る必要がある」ケースは、少なくとも符号付きと符号なしの場合で、時間を減算するときに注意する必要があるかどうかです。「結果を減算して出力する」だけの場合、署名されたtime_tがあるシステムでは期待どおりの結果が得られますが、署名されていないtime_tでは得られない可能性があります。
マイケルファース

@MichaelFirth整数の符号付きtime_tと符号なしのtime_tの両方にケースが存在し、生の減算により予期しない結果が生じます。Cはdouble difftime(time_t time1, time_t time0)、均一な減算アプローチを提供します。
chux-モニカを

-3

time_tすべてのコンパイラとOSが理解できるtypedef8バイト(long long/__int64)のみです。昔はlong int(4バイト)でしたが、今はそうではありません。あなたが見た場合time_tではcrtdefs.h、あなたは両方の実装を見つけるだろうが、OSが使用されますlong long


5
すべてのコンパイラとOS?いいえ。私のLinuxシステムでは、コンパイラーは4バイトの符号付き実装を採用しています。
Vincent

Zynq 7010システムでは、time_tは4バイトです。
フクロウ

1
組み込みシステムで私がtime_tで作業するのは、ほとんど常に32ビットまたは4バイトです。この規格は、具体的には、この答えを間違っているのは実装固有であると述べています。
Cobusve
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.