假設應該可移植到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位,它將會失敗,因爲最後三個常量太大而不適合。
解決此問題的一種方法是更改函數的接口和表的類型,以使用uint32_t
或uint64_t
。但是,如何將這與不使用這些類型的現有API結合起來,如__builtin_clzl()
或labs()
?
另一種方法是保持接口相同,但將函數內部的參數提升爲將支持的最大尺寸uint64_t,並將表格元素保存爲此大小。但是在32位系統上這是非常低效的。
可以安排提供一個宏來定義一個長整數的大小,然後將表的第二行放在#if
之內。這很難,因爲sizeof()
不適用於預處理器。需要像autoconf這樣的東西來確定大小並生成一個配置頭文件。這很難適應現有的構建過程。
在一個打算提供全套的符號/無符號int
,long int
和long long int
功能,這裏是另一種方式:
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和long long int是一定的大小,long int的大小與其中一個相等。目前存在的幾乎每個32位平臺都是如此。
有沒有更好的方法?
這似乎有問題。如果實現的'intmax_t'(或者'uintmax_t',如果常量是無符號的)不足以代表關係表達式右邊的常量,那麼我傾向於認爲關係表達式不會有期望的效果。 –
@JohnBollinger查看更新。你的關心是非常有效的。嵌套的方法應該解決它。我們可以確信,宏數學運算至少32位有符號,然後繼續工作。 – chux
您可以在宏數學中使用整數後綴 –