Использование stdint.h и ANSI printf? - PullRequest
2 голосов
/ 01 мая 2010

Я пишу библиотеку bignum и хочу использовать эффективные типы данных для представления цифр. Особенно целое для цифры и длинное (если строго удваивает размер целого) для промежуточных представлений при сложении и умножении.

Я буду использовать некоторые функции 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, которые полагаются исключительно на стандартные типы, я больше не знаю, что использовать.

Ответы [ 2 ]

3 голосов
/ 01 мая 2010

Вы можете использовать макросы из <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.

1 голос
/ 01 мая 2010

ANSI C не дает никаких гарантий относительно размеров int и long, и я не думаю, что long long является типом ANSI. Если вы не хотите или не можете использовать C99, единственное безопасное, переносимое решение - это написать скрипт конфигурации, который будет создавать программы на C, использующие sizeof, для поиска пары целочисленных типов, обладающих требуемым свойством. Затем в этом сценарии вы можете создавать макросы, включая макросы формата printf.

Также возможно, что вы не используете C99, потому что вы портируете на какую-то дурацкую платформу без компилятора C99. В этом случае вы можете просто выяснить, что работает, добавить это в заголовок и не беспокоиться о переносимости.

C99 не очень красив, но он определенно решает некоторые из этих раздражающих проблем с C.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...