【问题标题】:Generic function for comparing two integers?比较两个整数的通用函数?
【发布时间】:2013-05-07 02:22:10
【问题描述】:

是否有相当标准的 C (Linux) 函数或代码效率高但性能良好的方法来比较任意大小的两个整数?

我正在寻找带有参数int intcmp(const void *a, const void *b, size_t size) 的东西,它适用于整数ab,适用于任何实际大小size。 (memcmp() 会工作(我认为)如果架构是大端的。)

我倾向于使用的实现是这样的(从 Efficient integer compare function 改进),但它并不完全通用,并且有足够的代码开销,我通常会在插入之前三思而后行。

int intcmp(const void *a, const void *b, size_t size) {

    #define CASE_SIZE_RETURN_A_B_CMP(_t) \
        case sizeof(_t): \
            return ((*(_t *)(a) > *(_t *)(b)) - (*(_t *)(a) < *(_t *)(b)))

    switch (size) {
    CASE_SIZE_RETURN_A_B_CMP(char);
    CASE_SIZE_RETURN_A_B_CMP(short);
    CASE_SIZE_RETURN_A_B_CMP(int);
    CASE_SIZE_RETURN_A_B_CMP(long long);
    }
    #undef CASE_SIZE_RETURN_A_B_CMP

    assert(0);
    return 0;
}

【问题讨论】:

  • 我怀疑这是否有标准功能。请注意,如果您需要有符号和无符号类型,您的解决方案将不起作用。
  • 一旦你写到“任意大小的整数”,我认为你已经超出了“如果架构是大端”所涵盖的范围,因为那种低级架构考虑不允许任意大小的整数。相反,您需要决定您打算如何表示(例如)1024 位整数,然后相应地编写您的函数。
  • 为什么不在需要的地方使用更简单的宏内联版本?
  • 如果您的任意大小仅限于预定义的数据类型(看起来像您的帖子中的那样),我会采用您的方法,不使用宏,使用上述宏您不会获得任何东西,而是阅读起来更复杂。
  • 如果您在 C 程序中需要这样的函数,那么您可能做错了,即可能需要重新设计调用该函数的代码。如果你真的需要这样做,你应该考虑使用 C++ 及其模板或者 C11 的通用函数。如果没有其他可能,您的解决方案还不错,可能是您可以拥有的最好的解决方案(尽管我可能不会使用宏,尽管代码重复)。

标签: c


【解决方案1】:

静态内联函数的优点是参数只被评估一次(这对于宏来说很难/不可能)。这将允许像 int diff = cmp_all (p++, q++, sizeof *p); 这样的函数调用:

#include <stdlib.h>
#include <stdint.h>

static inline int cmp1(const int8_t *one, const int8_t *two)
{
if (*one < *two) return -1;
else if (*one > *two) return 1;
else return 0;
}

static inline int cmp2(const int16_t *one, const int16_t *two)
{
if (*one < *two) return -1;
else if (*one > *two) return 1;
else return 0;
}

static inline int cmp4(const int32_t *one, const int32_t *two)
{
if (*one < *two) return -1;
else if (*one > *two) return 1;
else return 0;
}

static inline int cmp8(const int64_t *one, const int64_t *two)
{
if (*one < *two) return -1;
else if (*one > *two) return 1;
else return 0;
}

int cmp_all(const void *one, const void *two, size_t size)
{
switch(size) {
case 1: return cmp1(one, two);
case 2: return cmp2(one, two);
case 4: return cmp4(one, two);
case 8: return cmp8(one, two);
default: return 0; /* that will teach them ... */
        }
}

【讨论】:

    【解决方案2】:

    如果您确实需要对任意大小的整数进行良好的比较,我建议您查看The GNU Multiple Precision Arithmetic Library。这需要您使用它的特殊 mpz_t 类型(包括长度)。然后你可以使用函数int mpz_cmp(mpz_t op1, mpz_t op2)。决定自己的大整数表示并以相当可移植和高效的方式实现它并非易事。

    另一方面,如果您只需要您提到的标准整数大小,我认为您的实现很好。但是为了更好的可移植性,您不应该对各种整数大小做出假设:

    #include <stdint.h>
    
    int intcmp(const void *a, const void *b, size_t size) {
        switch (size) {
        case 1: return (*(int8_t*)a > *(int8_t*)b) - (*(int8_t*)a < *(int8_t*)b)
        case 2: return (*(int16_t*)a > *(int16_t*)b) - (*(int16_t*)a < *(int16_t*)b)
        case 4: return (*(int32_t*)a > *(int32_t*)b) - (*(int32_t*)a < *(int32_t*)b)
        case 8: return (*(int64_t*)a > *(int64_t*)b) - (*(int64_t*)a < *(int64_t*)b)
        }
    
        assert(0);
        return 0;
    }
    

    也许您会发现为所需的每个长度创建一个单独的函数而不是对所有长度都使用相同的函数会更好?最后,如果效率很重要,使用 charshort 进行算术运算的效率通常低于使用 int。因此,请尽量避免需要使用 char 或 short 调用此函数并使用 int 的情况。

    【讨论】:

    • 问题在于,当a 是一个大的负数而b 是一个大的正数时,它会调用未定义的行为,反之亦然。您会遇到有符号算术溢出,这在实践中通常是良性的,但在形式上是未定义的行为,应该不惜一切代价避免。 sint8_t et al 等名称在 &lt;stdint.h&gt; 中没有根据 C 标准定义;有符号类型为int8_t,无符号类型为uint8_t。我有时会使用sintN_t 名称,但我知道这是一个非标准扩展名。
    • 是的,你是对的。我进行了修改以反映您的 cmets。
    【解决方案3】:

    我认为以下链接会有所帮助。您可以在不使用比较器的情况下进行比较,从而降低代码开销。我过去曾使用过与此链接相关的代码。

    -良好的狩猎-

    C program to compare integers without using logical operators?

    【讨论】:

    • 我会在生产中使用变体。将打印语句放在一边,我看到了可重用性,并且该功能适合任务。
    【解决方案4】:

    如果调用站点有可用的大小,我更愿意将其用作查找表中的索引,以便立即调用正确的函数。

    【讨论】:

    猜你喜欢
    • 2012-06-05
    • 1970-01-01
    • 1970-01-01
    • 2014-10-25
    • 2016-01-15
    • 2019-07-04
    • 1970-01-01
    • 2015-12-14
    • 2013-01-31
    相关资源
    最近更新 更多