防止有符号和无符号整数逻辑之间的代码重复

亚历克斯·拉夫里夫

我有以下功能:第一个在给定的基数(基数)中打印无符号整数。
第二个函数完全相同,但使用有符号整数。如您所见,这些函数的主体完全相同。为了防止将相同的代码加倍,我已经努力了几个小时,但我找不到解决此问题的方法。

无符号函数:

const char *digit = "0123456789abcdef";
int print_int_helper_unsigned(unsigned int n, int radix, const char *digit) {

  int result;

  if (n < radix) {

    putchar(digit[n]);

    return 1;
  }
  else {
    result = print_int_helper_unsigned(n / radix, radix, digit);

          putchar(digit[n % radix]);

    return 1 + result;
  }
}

签名函数:

int print_int_helper( int n, int radix, const char *digit) {

  int result;

  if (n < radix) {

    putchar(digit[n]);

    return 1;
  }
  else {
    result = print_int_helper(n / radix, radix, digit);

          putchar(digit[n % radix]);

    return 1 + result;
  }
}
名义动物

将递归部分重构为辅助函数:

static void fprintf_digits_recursive(FILE *out,
                                     const unsigned long radix,
                                     const char *digits,
                                     unsigned long value)
{
    if (value >= radix)
        fprintf_digits_recursive(out, radix, digits, value / radix);
    fputc(digits[value % radix], out);
}

我标记了它static,因为它应该只在这个编译单元(文件)中可见,而不能直接在外部调用。

辅助函数的目的是打印一个数字。如果value有多个数字,则首先打印较高的数字。(这就是为什么fputc()递归调用。)

有符号和无符号整数打印机因此使用帮助程序:

void print_int(const int value, const char *digits, const int radix)
{
    if (radix < 1 || !digits) {
        fprintf(stderr, "print_int(): Invalid radix and/or digits!\n");
        exit(EXIT_FAILURE);
    }

    if (value < 0) {
        fputc('-', stdout);
        fprintf_digits_recursive(stdout, radix, digits, (unsigned long)(-value));
    } else
        fprintf_digits_recursive(stdout, radix, digits, (unsigned long)(value));
}

void print_uint(const unsigned int value, const char *digits, const int radix)
{
    if (radix < 1 || !digits) {
        fprintf(stderr, "print_int(): Invalid radix and/or digits!\n");
        exit(EXIT_FAILURE);
    }

    fprintf_digits_recursive(stdout, radix, digits, (unsigned long)value);
}

我特意添加了输出流标识符并更改了参数顺序,以便更容易理解可见函数(有时也称为包装器函数,如果它们非常简单)与执行实际操作的实际内部辅助函数有何不同工作。

我在包装函数中添加了基数和数字检查,因为这是推荐的做法。(也就是说,不要将参数检查留给辅助函数,而是在包装函数中进行。这样,如果需要,您还可以提供“快速”/未检查版本的包装函数。)

同样的方法用于将重复的代码重构为帮助程序和实际的公共函数。您找到重复的代码,将其移动到一个单独的内部辅助函数,注意参数可能与公共函数使用的非常不同——通常,您可能有一个动态分配的缓冲区来放置数据。

没有真正困难的部分,你只需要练习一点,并学会在选择将哪些参数传递给辅助函数时考虑多个用户——最初重复的函数。

在非常复杂的情况下,您可能需要将辅助函数拆分为多个辅助函数;进入某种辅助工具箱这通常是动态内存管理辅助函数的情况。

例如,如果你想把它变成一个产生动态分配字符串的接口,你可以使用一个字符串缓冲区接口,比如

struct strbuffer {
    char   *data;
    size_t  size;   /* Number of chars allocated for */
    size_t  used;   /* Number of chars used in data */
};
#define STRBUFFER_INIT { NULL, 0, 0 }

static void strbuffer_addchar(struct strbuffer *ref, const char c);
static char *strbuffer_finalize(struct strbuffer *ref);
static char *strbuffer_finalize_reverse(struct strbuffer *ref);

这样有符号整数到字符串函数可能看起来像

char *new_int_to_string(const int value, const size_t radix, const char *digits)
{
    struct strbuffer buf = STRBUFFER_INIT;
    if (value < 0) {
        reverse_radix(&buf, radix, digits, -value);
        strbuffer_addchar(&buf, '-');
    } else
        reverse_radix(&buf, radix, digits, value);
    return strbuffer_finalize_reverse(&buf);
}

reverse_radix()以相反的顺序构建数值,

void reverse_radix(struct strbuffer *ref,
                   const unsigned long radix,
                   const char *digits,
                   unsigned long value)
{
    do {
        strbuffer_addchar(ref, digits[value % radix]);
        value /= radix;
    } while (value > 0);
}

辅助函数strbuffer_finalize()data字段重新分配到所需的确切长度,包括字符串终止\0,清除结构,并返回data; strbuffer_finalize_reverse()做同样的事情,除了先反转内容。这样我们也把递归调用变成了一个简单的循环。

您甚至可以使用 strbuffer 助手实现浮点版本;您只需将整数部分与小数部分分开转换(还有两个辅助函数)。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

有符号整数和无符号整数

有符号和无符号整数

有符号整数到无符号整数和DWORD的转换

有符号和无符号整数表达式与0x80000000之间的比较

C ++有符号和无符号整数表达式之间的比较

c ++:有符号和无符号整数表达式之间的比较

有符号和无符号整数表达式之间的比较

消除有符号和无符号整数表达式之间比较的绝佳方法

警告:有符号和无符号整数表达式之间的比较..如何解决?

在C#中缩小有符号和无符号整数类型之间的转换

C编译器如何处理无符号和有符号整数?为什么无符号和有符号算术运算的汇编代码相同?

在有符号和无符号之间进行隐式转换的c ++代码安全性

代码限定-libc的qsort中有符号和无符号值之间的比较

概括添加无符号和有符号整数类型

比较有符号和无符号整数安全吗?

仅带符号的整数的“带符号的和无符号的整数表达式之间的比较”

C ++:<=有符号和无符号之间的冲突

有符号和无符号之间的减法,然后除法

C中有符号和无符号字符之间的区别

有符号和无符号字符之间的比较

IA32汇编代码,用于从有符号/无符号字符到无符号/有符号整数的类型转换

C ++现在:有符号和无符号整数表达式之间的比较(Freebsd,GCC,Gmake)

如何修复它“有符号和无符号整数表达式之间的比较 [-Werror=sign-compare]”

减去无符号整数的有符号结果?

模数和无符号整数

有符号/无符号字符之间的区别

从char数组转换为16位有符号整数和32位无符号整数

C如何将负数存储为有符号整数和无符号整数?

模板区分有符号和无符号