2017-04-03 104 views
2

假設應該可移植到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_tuint64_t。但是,如何將這與不使用這些類型的現有API結合起來,如__builtin_clzl()labs()

另一種方法是保持接口相同,但將函數內部的參數提升爲將支持的最大尺寸uint64_t,並將表格元素保存爲此大小。但是在32位系統上這是非常低效的。

可以安排提供一個宏來定義一個長整數的大小,然後將表的第二行放在#if之內。這很難,因爲sizeof()不適用於預處理器。需要像autoconf這樣的東西來確定大小並生成一個配置頭文件。這很難適應現有的構建過程。

在一個打算提供全套的符號/無符號intlong intlong 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位平臺都是如此。

有沒有更好的方法?

回答

3

考慮一系列#if

#include <limits.h> 
const unsigned long int powers[] = { 
    0, 1000, 1000000, 1000000000 
    #if ULONG_MAX/1000 >= 1000000000 
     , 1000000000000u 
    #endif 
    #if ULONG_MAX/1000 >= 1000000000000 
     , 1000000000000000u 
    #endif 
    #if ULONG_MAX/1000 >= 1000000000000000 
     , 1000000000000000000u 
    #endif 
    }; 

這上面的方法確實有困難的「宏觀數學」簽訂有時(根據經驗,不符合規範),所以下面的代碼做出合理的假設「嵌套」方法更好,因爲它可以確保「宏觀數學」的工作取決於先前的成功,對於C99,11編譯器來說這並不重要,因爲數學至少爲64這比較老的編譯器或者如果有人想把這個方案擴展到比64-b更寬的地方,這會產生更多的差異它unsigned long

#if LONG_MAX/1000 >= 500000000 
     , 1000000000000u 
     #if LONG_MAX/1000 >= 500000000000 
     , 1000000000000000u 
     #if LONG_MAX/1000 >= 5000000000000000 
      , 1000000000000000000u 
      #if LONG_MAX/1000 >= 5000000000000000000 
      #error powers[] needs extending 
      #endif 
     #endif 
     #endif 
    #endif 

「宏數學」或更好預處理器算術,與在C11至少64位數學(和可能C99)完成,但僅僅至少32位與早期像C89。

對於此令牌轉換和評價,所有符號整數類型和所有無符號整數類型的目的充當如果它們具有相同的表示爲分別的類型intmax_tuintmax_t在頭<stdint.h>定義。)此包括解釋字符常量,這可能涉及將轉義序列轉換爲執行字符集成員。 C11§6.10.14

+0

這似乎有問題。如果實現的'intmax_t'(或者'uintmax_t',如果常量是無符號的)不足以代表關係表達式右邊的常量,那麼我傾向於認爲關係表達式不會有期望的效果。 –

+0

@JohnBollinger查看更新。你的關心是非常有效的。嵌套的方法應該解決它。我們可以確信,宏數學運算至少32位有符號,然後繼續工作。 – chux

+1

您可以在宏數學中使用整數後綴 –

0

你可以考慮給表元素類型unsigned long long intuintmax_t(這可能是也可能不是同樣的事情)。任何符合C99或C11的實現將提供至少64位寬的unsigned long long int,因此uintmax_t也將至少那麼寬。

當然,這引出了你的函數如何處理大於64位的輸入的問題。

相關問題