回答:
ウィキペディアの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年問題の影響を受けます。
time_t
ディスク上のデータ構造での使用が発生する可能性があります。ただし、ファイルシステムは他のオペレーティングシステムによって読み取られることが多いため、このような実装に依存するタイプに基づいてファイルシステムを定義することは愚かなことです。たとえば、32ビットシステムと64ビットシステムの両方で同じファイルシステムが使用され、time_t
サイズが変更される場合があります。したがって、ファイルシステムは、より厳密に定義する必要があります(「1970年の開始からの秒数を表す32ビットの符号付き整数、UTCで」)time_t
。
time.h
コンテンツのリストにリダイレクトされるようになりました。その記事のcppreference.comへのリンクが、コンテンツがどこにも見つからないです引用...
time_t
が署名済みであることを保証しているという主張は誤りです。pubs.opengroup.org/onlinepubs/9699919799/basedefs/…は、さまざまなものが「符号付き整数型」または「符号なし整数型」でなければならないことを示していますが、「整数型でなければならない」time_t
とだけ述べています。実装により、署名なしにしても、POSIXに準拠できます。time_t
[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
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)。
__time_t
ないtime_t
のtime_t
ですか?ステップを省略しますか?
typedef __time_t time_t;
typedefが実際に使用され、条件付きコンパイルの一部だけではないことを確認するために、周囲のコードの検査も必要であることを思い出しました。 typedef long time_t;
も発見された可能性があります。
規格
ウィリアム・ブレンデルはウィキペディアを引用したが、私は馬の口からそれを好む。
C99 N1256標準ドラフト 7.23.1 / 3「時間の構成要素」は次のように述べています。
宣言されたタイプは、size_t(7.17で説明)clock_tおよびtime_tであり、時間を表すことができる算術タイプです。
および6.2.5 / 18「タイプ」と言います。
整数型と浮動小数点型はまとめて算術型と呼ばれます。
[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からの入力gcc -E -xc -include time.h /dev/null | grep time_t
答えは間違いなく実装固有です。ご使用のプラットフォーム/コンパイラーを明確に見つけるには、コードのどこかにこの出力を追加します。
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);
新しい質問:その考えの根拠は何ですか?
%zu
フォーマットに書式指定子をsize_t
(によって得られたような値sizeof
)は、符号なしているとして(、 u
()と長さsize_t型のz
・)
printf ("sizeof time_t is: %d\n", (int) sizeof(time_t));
して回避しz
ます。
Visual Studio 2008では、__int64
を定義しない限り、デフォルトでに設定されます_USE_32BIT_TIME_T
。それがどのように定義されているのかがわからないふりをする方がよいでしょう。
time_t
long int
64ビットマシンのタイプですlong long int
。それ以外の場合はです。
これらのヘッダーファイルでこれを確認できます。
time.h
:/usr/include
types.h
とtypesizes.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;
long int
どこにでもあるわけではありません。stackoverflow.com/questions/384502/…を
これは、ほとんどのレガシープラットフォームでは32ビットの符号付き整数型です。ただし、これによりコードは2038年のバグに悩まされます。したがって、最新のCライブラリでは、署名された64ビットintとして定義する必要があります。これは、数十億年間安全です。
通常、これらのgccの実装固有のtypedefは、bits
またはasm
ヘッダーディレクトリにあります。私にとってはです/usr/include/x86_64-linux-gnu/bits/types.h
。
単にgrepするか、Quassnoiが提案するようなプリプロセッサ呼び出しを使用して、特定のヘッダーを確認できます。
最終的には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);
double difftime(time_t time1, time_t time0)
、均一な減算アプローチを提供します。
time_t
すべてのコンパイラとOSが理解できるtypedef
8バイト(long long/__int64
)のみです。昔はlong int
(4バイト)でしたが、今はそうではありません。あなたが見た場合time_t
ではcrtdefs.h
、あなたは両方の実装を見つけるだろうが、OSが使用されますlong long
。
long int
ます。