web-dev-qa-db-ja.com

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

Linuxボックスを検索して、このtypedefを見ました:

typedef __time_t time_t;

しかし、__time_t定義が見つかりませんでした。

182
kal

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年問題 の影響を受けやすくなっています。

159
William Brendel

[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
101
Quassnoi

規格

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);

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

12
pwrgreg007

Visual Studio 2008では、__int64を定義しない限り、デフォルトで_USE_32BIT_TIME_Tになります。プラットフォームごとに変化する可能性がある(そして変化する)ので、それが何として定義されているかわからないふりをしたほうがよいでしょう。

7
Eclipse

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;
5
abcoep

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

4
user

通常、bitsまたはasmヘッダーディレクトリに、これらのgccの実装固有のtypedefがあります。私にとっては、/usr/include/x86_64-linux-gnu/bits/types.hです。

単にgrepするか、 Quassnoiが提案するようなプリプロセッサ呼び出し を使用して、どの特定のヘッダーを確認することができます。

3
poolie

最終的に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);
1
chux