【问题标题】:Using stdint.h and ANSI printf?使用 stdint.h 和 ANSI printf?
【发布时间】:2011-02-14 09:38:46
【问题描述】:

我正在编写一个 bignum 库,我想使用高效的数据类型来表示数字。特别是整数表示数字,long(如果严格是整数大小的两倍)用于加法和乘法时的中间表示。

我将使用一些 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;

由于我还没有编写将 bignum 写入十进制的程序,因此我必须分析中间数组并打印每个数字的值。但是我不知道 printf 使用哪个转换说明符。最好我想将十六进制编码的数字写入终端。

根本问题是,我想要两种数据类型,一种是另一种的两倍,然后使用标准转换说明符进一步将它们与 printf 一起使用。如果 int 是 32 位并且 long 是 64 位,那将是理想的,但我不知道如何使用预处理器来保证这一点,并且当需要使用诸如 printf 之类的仅依赖于标准类型的函数时,我不再知道要做什么使用。

【问题讨论】:

    标签: c types printf


    【解决方案1】:

    您可以使用来自 &lt;inttypes.h&gt; 的宏来提供帮助:

    #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 的做法。

    【讨论】:

    • 您的意思是用双引号将定义括起来?无论如何,方便的提示。我认为这将记录在 printf 手册页中,但我想知道 C99 将如何处理这些类型。谢谢。
    • 在定义它们的示例的第一部分中,PRI_U_HWPRI_U_W 只是 C99 PRIuXX 值的别名,它们将是字符串文字。当您使用它们时(如在第二个代码 sn-p 中的 2 个 printf() 示例中),您必须在引号之外使用它们(它们提供自己的引号)并依赖于 C 在 ' 中执行的相邻字符串文字的串联翻译的第 6 阶段。就像我说的,它有点丑。
    • 我明白了。顺便说一句,您认为有什么办法可以避免这种处理器垃圾并坚持使用 int/long 吗?我真的只需要两种类型,其中一种至少是宽度的两倍。我猜 char 和 short 可以解决问题,但如果可能的话,我更喜欢使用更大的数据类型,例如 int/long/long long。
    • @nn:我可能会考虑只使用 uint32_t 和 uint64_t。我认为几乎所有 32 位编译器都支持 64 位 int 类型(即使它不是 long long,例如 VC6 具有 __int64 类型)。但是您必须能够说您限制了对具有 64 位 int 类型的编译器的支持,只有您可以说这是否可以接受。
    【解决方案2】:

    ANSI C 不保证intlong 的大小,我不认为long long 是ANSI 类型。如果您不愿意或无法使用 C99,唯一安全、可移植的解决方案是编写一个配置脚本,该脚本将创建 C 程序,该程序使用 sizeof 来查找具有您需要的属性的一对整数类型。然后,您可以在该脚本中生成包括printf 格式宏的宏。

    您不使用 C99 的原因也可能是因为您正在移植到一些没有 C99 编译器的古怪平台。在这种情况下,您只需找出有效的方法,将其放在标题中,而不必担心可移植性。

    C99 并不漂亮,但它确实解决了一些令人讨厌的 C 问题。

    【讨论】:

    • 感谢您揭开这个过程的神秘面纱。我想这就是大多数 autoconf 程序所做的。你会手动建议,还是有一些工具来完成这项艰巨的工作?我只知道 autoconf,开始一个小项目似乎很复杂。
    • @nn:我从 GNU 自动工具中尖叫。我建议使用手写的 POSIX sh 脚本。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-11
    • 1970-01-01
    • 2020-10-26
    • 2021-10-26
    • 2018-07-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多