2010-04-30 53 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