(u)int_(fast/least)XX_t
私の知る限り、コンパイラは、システムによってまだ定義されていない場合にのみ、独自のバージョンの型を定義します。これは、これらの型が単一システム上のすべてのライブラリ/バイナリで等しく定義されていることが非常に重要だからです。それ以外の場合、異なるコンパイラがこれらの型を異なる方法で定義する場合、CompilerA でビルドされたライブラリは CompilerBuint_fast32_t
でビルドされたバイナリとは異なる型を持つ可能性がありますが、このバイナリはライブラリに対してリンクする可能性があります。システムのすべての実行可能コードが同じコンパイラーによってビルドされなければならないという正式な標準要件はありません(実際には、Windows などの一部のシステムでは、コードがあらゆる種類の異なるコンパイラーによってコンパイルされているのが一般的です)。このバイナリがライブラリの関数を呼び出すと、問題が発生します!
問題は、ここで uint_fast16_t を定義するのは本当に GCC なのか、それとも実際に Linux (ここではカーネルを意味する) なのか、あるいはそれらの型を定義する標準 C Lib (ほとんどの場合 glibc) なのか? Linux または glibc がこれらを定義している場合、そのシステム上に構築された GCC は、これらが確立した規則を採用する以外に選択肢がありません。他のすべての可変幅型にも同じことが言えます: char
, short
, int
, long
, long long
; これらの型はすべて、C 標準で保証されている最小ビット幅しかありません(int
実際には 16 ビットであるため、int
32 ビットのプラットフォームでは、標準で必要とされるよりもはるかに大きくなっています)。
それ以外では、CPU/コンパイラ/システムのどこが悪いのだろうか。私のシステムでは、64 ビットの乗算は 32 ビットの乗算と同等に高速です。16、32、および 64 ビットをテストするようにコードを変更しました。
#include <time.h>
#include <stdio.h>
#include <inttypes.h>
#define RUNS 100000
#define TEST(type) \
static type test ## type () \
{ \
int count; \
type p, x; \
\
p = 1; \
for (count = RUNS; count != 0; count--) { \
for (x = 1; x != 50000; x++) { \
p *= x; \
} \
} \
return p; \
}
TEST(uint16_t)
TEST(uint32_t)
TEST(uint64_t)
#define CLOCK_TO_SEC(clock) ((double)clockTime / CLOCKS_PER_SEC)
#define RUN_TEST(type) \
{ \
clock_t clockTime; \
unsigned long long result; \
\
clockTime = clock(); \
result = test ## type (); \
clockTime = clock() - clockTime; \
printf("Test %s took %2.4f s. (%llu)\n", \
#type, CLOCK_TO_SEC(clockTime), result \
); \
}
int main ()
{
RUN_TEST(uint16_t)
RUN_TEST(uint32_t)
RUN_TEST(uint64_t)
return 0;
}
最適化されていないコード (-O0) を使用すると、次のようになります。
Test uint16_t took 13.6286 s. (0)
Test uint32_t took 12.5881 s. (0)
Test uint64_t took 12.6006 s. (0)
最適化されたコード (-O3) を使用すると、次のようになります。
Test uint16_t took 13.6385 s. (0)
Test uint32_t took 4.5455 s. (0)
Test uint64_t took 4.5382 s. (0)
2 番目の出力は非常に興味深いものです。@R .. は上記のコメントに次のように書いています。
x86_64 では、32 ビット演算が 64 ビット演算より遅くなることはありません。
2 番目の出力は、32/16 ビット演算については同じことが言えないことを示しています。私の x86 CPU は 16 ビット演算をネイティブに実行できますが、32/64 ビット CPU では 16 ビット演算が大幅に遅くなる可能性があります。たとえば、32 ビット演算しか実行できない PPC などの他の CPU とは異なります。ただし、これは私の CPU の乗算にのみ適用されるようです。コードを変更して加算/減算/除算を行うと、16 ビットと 32 ビットの間に大きな違いはなくなりました。
上記の結果は Intel Core i7 (2.66 GHz) のものですが、興味のある方は、このベンチマークを Intel Core 2 Duo (1 世代前の CPU) および Motorola PowerPC G4 でも実行できます。