LP64およびILP32システムに移植する必要がある関数、つまりlong int
は32または64ビットであるとします。この関数はいくつかの定数テーブルを持ちますが、定数そのものは型の幅に基づいている必要があります。不自然な例:整数型のサイズに依存するルックアップテーブル
// Find largest power of 1000 less than x, aka log base 1000 rounded down to an integer
unsigned long int intlog1000l(unsigned long int x) {
const unsigned long int powers[] = {
0, 1000, 1000000, 1000000000,
1000000000000, 1000000000000000, 1000000000000000000 };
unsigned int i;
for (i = 0; i < sizeof(powers)/sizeof(*powers); i++)
if (powers[i] > x) break;
return i - 1;
}
long int
場合は、意図したように、このコードは動作し、64ビットです。しかし、long int
が32ビットの場合、最後の3つの定数が大きすぎてフィットしないため、失敗します。
これを回避する1つの方法は、関数のインターフェイスとテーブルのタイプを両方ともuint32_t
またはuint64_t
に変更することです。しかし、これを__builtin_clzl()
やlabs()
など、これらのタイプを使用しない既存のAPIとどう組み合わせることができますか?
もう1つの方法は、インターフェイスを同じに保つことですが、関数内の引数をサポートされる最大サイズuint64_tに昇格させ、このサイズのテーブル要素を保存したままにしておきます。しかし、それは32ビットシステムでは非常に非効率的です。
長い整数のサイズを定義するマクロを提供し、テーブルの2行目を#if
の内側に配置するように調整できます。 sizeof()
はプリプロセッサでは使用できないため、これは困難です。サイズを決定して設定ヘッダーを生成するには、autoconfのようなものが必要です。これは、既存のビルドプロセスに適合するのが難しいです。
unsigned int intlog1000(unsigned int); // assume 32 bits
unsigned long long int intlog1000ll(unsigned long long int); // assume 64 bits
static inline unsigned long int intlog1000l(unsigned long int x)
{ sizeof(x) == sizeof(unsigned int) ? intlog1000(x) : intlog1000ll(x); }
このことはintに仮定しても安全になるという仮定を作り、:1で
が署名/署名のないint
、long int
、およびlong long int
機能のフルセットを提供することを目的とする、ここでは別の方法ですlong long intは特定のサイズであり、long intはサイズがどちらかと同じになります。これは現在存在するほぼすべての32ビットプラットフォームでのケースです。
もっと良い方法がありますか?
これは問題があるようです。実装の 'intmax_t'(または定数が符号なしであれば' uintmax_t')が関係式の右辺の定数を表現するのに十分な大きさでなければ、関係式にはないと思う傾向があります所望の効果。 –
@JohnBollinger更新を参照してください。あなたの懸念は非常に有効です。ネストされたアプローチはそれに対処する必要があります。マクロの数学は最低でも32ビットで動作し、その後はうまくいくと確信できます。 – chux
マクロの数値式 –