2010-04-30 58 views
2

我正在寫一個bignum庫,我想用高效的數據類型來表示數字。特別是數字的整數,以及在加法和乘法時對於中間表示的長整數(如果嚴格是整數大小的兩倍)。使用stdint.h和ANSI printf?

我會用一些C99的功能,而是試圖符合ANSI C.

目前我已經在我的BIGNUM庫如下:

#include <stdint.h> 

#if defined(__LP64__) || defined(__amd64) || defined(__x86_64) || defined(__amd64__) || defined(__amd64__) || defined(_LP64) 
typedef uint64_t u_w; 
typedef uint32_t u_hw; 
#define BIGNUM_DIGITS 2048 
#define U_HW_BITS 16 
#define U_W_BITS 32 
#define U_HW_MAX UINT32_MAX 
#define U_HW_MIN UINT32_MIN 
#define U_W_MAX UINT64_MAX 
#define U_W_MIN UINT64_MIN 
#else 
typedef uint32_t u_w; 
typedef uint16_t u_hw; 
#define BIGNUM_DIGITS 4096 
#define U_HW_BITS 16 
#define U_W_BITS 32 
#define U_HW_MAX UINT16_MAX 
#define U_HW_MIN UINT16_MIN 
#define U_W_MAX UINT32_MAX 
#define U_W_MIN UINT32_MIN 
#endif 

typedef struct bn 
{ 
     int sign; 
     int n_digits; // #digits should exclude carry (digits = limbs) 
     int carry; 
     u_hw tab[BIGNUM_DIGITS]; 
} bn; 

由於我沒有寫一個程序寫十進制的數字,我必須分析中間數組,並且輸出每個數字的值。但是我不知道使用printf的轉換說明符。最好我想寫一個十六進制編碼的數字給終端。

根本問題是,我想要兩種數據類型,一種是另一種的兩倍,並進一步使用printf使用標準轉換說明符。如果int是32位,long是64位,但是我不知道如何使用預處理器來保證這一點,並且當使用完全依賴於標準類型的printf等函數時,我將不會知道該怎麼做使用。

回答

3

你可以使用宏從<inttypes.h>助陣:

#if defined(__LP64__) || defined(__amd64) || defined(__x86_64) || defined(__amd64__) || defined(__amd64__) || defined(_LP64) 
typedef uint64_t u_w; 
typedef uint32_t u_hw; 
#define BIGNUM_DIGITS 2048 
#define U_HW_BITS 16 
#define U_W_BITS 32 
#define U_HW_MAX UINT32_MAX 
#define U_HW_MIN UINT32_MIN 
#define U_W_MAX UINT64_MAX 
#define U_W_MIN UINT64_MIN 
#define PRI_U_HW PRIu32 // use for formatting a `u_hw` type 
#define PRI_U_W PRIu64 // use for formatting a `u_w` type 
#else 
typedef uint32_t u_w; 
typedef uint16_t u_hw; 
#define BIGNUM_DIGITS 4096 
#define U_HW_BITS 16 
#define U_W_BITS 32 
#define U_HW_MAX UINT16_MAX 
#define U_HW_MIN UINT16_MIN 
#define U_W_MAX UINT32_MAX 
#define U_W_MIN UINT32_MIN 
#define PRI_U_HW PRIu16 // use for formatting a `u_hw` type 
#define PRI_U_W PRIu32 // use for formatting a `u_w` type 
#endif 

然後:

printf("some u_w variable: %" PRI_U_W "\n", u_w_var);  
printf("some u_hw variable: %" PRI_U_HW "\n", u_hw_var); 

他們不漂亮,但他們C99是怎麼做的。

+0

你的意思是用雙引號括起定義? 反正,方便的提示。我認爲這將記錄在printf手冊頁中,但我想知道C99如何處理這些類型。 謝謝。 – snap 2010-04-30 20:39:51

+1

在定義例子的第一部分,'PRI_U_HW'和'PRI_U_W'只是C99'PRIuXX'值的別名,它們將是字符串文字。當你去使用它們時(如第二代碼片段中的2'printf()'例子),你必須在引號之外使用它們(它們提供自己的引號)並且依賴於C中的相鄰字符串連接的連接,階段6'的翻譯。就像我說的那樣,這有點難看。 – 2010-04-30 20:45:29

+0

我明白了。順便說一下,你認爲無論如何要避免這個處理器垃圾並堅持int/long?我真的只需要兩種類型,其中一種至少是寬度的兩倍。我猜字符和短會做的伎倆,但我寧願使用較大的數據類型,如int/long/long long,如果可能的話。 – snap 2010-04-30 21:02:19

1

ANSI C不提供關於尺寸intlong的保證,我不認爲long long是ANSI類型。如果您不願意或無法使用C99,唯一安全的便攜式解決方案是編寫一個配置腳本,該腳本將創建C程序,該程序使用sizeof來查找一對具有所需屬性的整數類型。然後您可以在該腳本中生成包括printf格式宏的宏。

也有可能你不使用C99的原因是你正在移植到一個沒有C99編譯器的古怪平臺。在這種情況下,你可以弄清楚什麼起作用,將它放在標題中,而不用擔心可移植性。

C99並不漂亮,但它肯定能解決一些令人討厭的C問題。

+0

感謝您揭開這個過程的神祕面紗。我想這是大多數autoconf程序所做的。你會用手提出建議,還是有一些工具可以付出艱辛的努力?我只知道autoconf,開始一個小項目似乎很複雜。 – snap 2010-05-01 03:41:06

+0

@nn:我從GNU autotools中運行尖叫。我會建議用手寫一個POSIX sh腳本。 – 2010-05-01 14:38:23