Linuxボックスを検索して、このtypedefを見ました:
typedef __time_t time_t;
しかし、__time_t
定義が見つかりませんでした。
time_tウィキペディアの記事 の記事は、これにいくらかの光を当てています。要するに、time_t
の型はC仕様では保証されていません。
time_t
データ型は、システム時刻値を格納するために定義されたISO Cライブラリのデータ型です。このような値は、標準のtime()
ライブラリ関数から返されます。この型は、標準ヘッダーで定義されたtypedefです。 ISO Cはtime_tを算術型として定義しますが、特定の型、範囲、解像度、またはエンコードを指定しません。また、時間値に適用される算術演算の意味も指定されていません。UnixおよびPOSIX準拠のシステムは、
time_t
型を、signed integer
(通常32ビットまたは64ビット幅)として実装します。これは、Unixエポックの開始からの秒数を表します:1970年1月1日の深夜UTC(うるう秒はカウントしません)。負の時間値を正しく処理するシステムもあれば、そうでないシステムもあります。 32ビットのtime_t
型を使用するシステムは、 2038年問題 の影響を受けやすくなっています。
[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
規格
William Brendel Wikipediaを引用したが、私は馬の口からそれを好む。
C99 N1256標準ドラフト7.23.1/3 "時間のコンポーネント"言います:
宣言される型は、size_t(7.17で説明)clock_tおよびtime_tです。これらは、時刻を表すことができる算術型です。
および6.2.5/18 "Types"言う:
整数型と浮動小数点型は、算術型と総称されます。
POSIX 7 sys_types.h 言います:
[CX] time_tは整数型でなければなりません。
ここで、[CX]
は 定義 :
[CX] ISO C標準の拡張。
これは拡張機能であり、より強力な保証が行われます。つまり、浮動小数点が出力されます。
gccワンライナー
前述のようにファイルを作成する必要はありません by 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からの入力答えは間違いなく実装固有です。ご使用のプラットフォーム/コンパイラーを明確に調べるには、次の出力をコードのどこかに追加します。
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に)読み戻すだけで、Epochオフセット時間が得られます。同様の回避策が.Netに存在します。 WinとLinuxシステム間で64ビットエポック番号を問題なく渡します(通信チャネル経由)。これはバイト順序の問題を引き起こしますが、それは別の問題です。
Paxdiabloの質問に答えるには、プログラムがこのように書かれているため(「80年代」に自分でこれを行ったことを認めます)、「19100」と表示されたと思います。
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);
新しい質問:その考え方の根拠は何ですか?
Visual Studio 2008では、__int64
を定義しない限り、デフォルトで_USE_32BIT_TIME_T
になります。プラットフォームごとに変化する可能性がある(そして変化する)ので、それが何として定義されているかわからないふりをしたほうがよいでしょう。
time_t
は、64ビットマシンではlong int
タイプです。それ以外の場合はlong long int
です。
次のヘッダーファイルでこれを確認できます。
time.h
:/usr/include
types.h
およびtypesizes.h
:/usr/include/x86_64-linux-gnu/bits
(以下のステートメントは次々にありません。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;
ほとんどのレガシープラットフォームでは、32ビットの符号付き整数型です。ただし、これにより、コードが 2038年バグ の影響を受けます。そのため、最新のCライブラリでは、代わりに署名付き64ビットintとして定義する必要があります。これは、数十億年間安全です。
通常、bits
またはasm
ヘッダーディレクトリに、これらのgccの実装固有のtypedefがあります。私にとっては、/usr/include/x86_64-linux-gnu/bits/types.h
です。
単にgrepするか、 Quassnoiが提案するようなプリプロセッサ呼び出し を使用して、どの特定のヘッダーを確認することができます。
最終的にtime_t typedefとは何ですか?
堅牢なコードは、型が何であるかを気にしません。
C種time_t
は、double, long long, int64_t, int
などの実際の型.
エラーを示す多くの時間関数からの戻り値は-1
ではなく、(time_t)(-1)
であるため、unsigned
である可能性もあります-この実装の選択は一般的ではありません。
ポイントは、タイプを「知る必要がある」ということはまれであるということです。必要性を避けるためにコードを書く必要があります。
しかし、コードが生のtime_t
を出力したい場合、一般的な「知っておく必要がある」ことが発生します。最も広い整数型にキャストすると、ほとんどの最新のケースに対応できます。
time_t now = 0;
time(&now);
printf("%jd", (intmax_t) now);
// or
printf("%lld", (long long) now);
double
またはlong double
へのキャストも機能しますが、inexact10進出力を提供できます
printf("%.16e", (double) now);