首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >类strcmp接口用于比较C中的数字

类strcmp接口用于比较C中的数字
EN

Stack Overflow用户
提问于 2021-03-31 11:44:43
回答 2查看 120关注 0票数 0

我想要制作比较数字的strcmp-like接口,例如,在C中返回int > 0 if x > y0 if x = y< 0 if x < yncmp(x, y) (而不是C++)。

虽然我不一定要限制这些类型,但我的主要兴趣是比较signed long ints和doubles,“接口”可以是宏,比如tgmath.h,也可以是(一组)函数。我希望所有对signed long intdouble都能工作;例如,(signed long int, double)(double, double)应该可以工作。

我目前使用的是以下宏:

代码语言:javascript
复制
#define ncmp(x, y) ((x) > (y)) - ((x) < (y))

这个天真的宏有什么缺陷吗?有没有一个更好的,稳健的解决方案来比较数字?

任何帮助都将不胜感激!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-03-31 12:32:12

,我希望所有的signed long intdouble都能工作;

由于C11,代码可以使用_Generic来引导基于类型的函数选择。

代码语言:javascript
复制
int cmp_long(long x, long y) {
  return (x > y) - (x < y);
}  

int cmp_double(double x, double y) {
  return (x > y) - (x < y);
}  

#define cmp(X, Y) _Generic((X) - (Y), \
    long: cmp_long((X),(Y)), \
    double: cmp_double((X),(Y)) \
)

这种方法不能很好地检测X, Y属于不同类型的情况,因为(X) - (Y)使用它们之间的公共类型( @Ian Abbott )。然而,这是一个开始。

代码语言:javascript
复制
int main(void) {
  printf("%d\n", cmp(1L, 2L));
  printf("%d\n", cmp(3.0, 4.0));
}

可以制作一种更复杂的两阶段_Generic来区分long, doubledouble, long.我把那部分留给OP。

比较函数如下所示。与long相比,棘手的部分是不丢失double的精度(可能是64位)。

代码语言:javascript
复制
// TBD: handling of NANs
#define DBL_LONG_MAX_P1 ((LONG_MAX/2 + 1)*2.0)
int cmp_long_double(long x, double y) {
  // These 2 compares are expected to be exact - no rounding
  if (y >= DBL_LONG_MAX_P1) return -1;
  if (y < (double)LONG_MIN) return 1;

  // (long) y is now in range of `long`.  (Aside from NANs)
  long y_long = (long) y; // Lose the fraction
  if (y_long > x) return -1;
  if (y_long < x) return 1;
 
  // Still equal, so look at fraction
  double whole;
  double fraction = modf(y, &whole);
  if (fraction > 0.0) return -1;
  if (fraction < 0.0) return 1;
  return 0;
}

可能存在简化。

double准确地编码所有long或当long double存在并对所有long进行精确编码时,最容易将longdouble转换为公共类型并进行比较。

票数 2
EN

Stack Overflow用户

发布于 2021-03-31 13:50:46

对于这个宏:

代码语言:javascript
复制
#define ncmp(x, y) ((x) > (y)) - ((x) < (y))

主要问题是:

  1. --它需要在展开中增加一组括号才能形成主expression.There --在展开中没有足够的括号将其转换为主表达式。它应该是:

#定义ncmp(x,y) (X)> (y)) - ((x) <(Y)

  1. 它对(x)(y)进行了两次评估,如果评估有副作用,这可能是一个问题。

为了避免多重计算的问题,宏展开可以使用泛型选择表达式为每种类型的比较调用不同的函数。

注释1:在2011年版本的C标准(C11)中添加了泛型选择。

下面是一个使用泛型选择的宏示例。它可能需要扩展以支持其他类型:

代码语言:javascript
复制
#define ncmp(x, y) _Generic((x) < (y), \
    int: ncmp_si,                      \
    unsigned: ncmp_ui,                 \
    long: ncmp_sli,                    \
    unsigned long: ncmp_uli,           \
    long long: ncmp_slli,              \
    unsigned long long: ncmp_ulli,     \
    float: ncmp_f,                     \
    double: ncmp_d,                    \
    long double: ncmp_ld               \
    )((x), (y))

注释2:不计算泛型选择((x) < (y))的控制表达式,但它的类型用于选择相应的泛型关联表达式(如果有的话)。注意3:在控制表达式中选择<并不重要,但至少要检查(x)(y)是否有有序的关系。对于算术操作数,控制表达式的类型是通常算术转换的结果。注4:由于通常在控制表达式中对<的操作数进行算术转换,因此不需要为int级别以下的整数类型添加大小写。注5:可以添加default:泛型关联。例如,可以将其定义为回到使用不太安全的多重评估方法,如下所示:

代码语言:javascript
复制
#define ncmp(x, y) _Generic((x) < (y),         \
    int: ncmp_si((x), (y)),                    \
    unsigned: ncmp_ui((x), (y)),               \
    long: ncmp_sli((x), (y)),                  \
    unsigned long: ncmp_uli((x), (y)),         \
    long long: ncmp_slli((x), (y)),            \
    unsigned long long: ncmp_ulli((x), (y)),   \
    float: ncmp_f((x), (y)),                   \
    double: ncmp_d((x), (y)),                  \
    long double: ncmp_ld((x), (y)),            \
    default: ((x) > (y)) - ((x) < (y))         \
    )

,但我选择由程序员来添加缺少的情况。

有必要定义上述每个泛型关联所使用的函数。为了保存一些类型,可以定义一个助手宏来定义它们:

代码语言:javascript
复制
#define MK_NCMP_(suf, T) \
static inline int ncmp_##suf(T x, T y) { return (x > y) - (x < y); }

MK_NCMP_(si, int)
MK_NCMP_(ui, unsigned)
MK_NCMP_(sli, long)
MK_NCMP_(uli, unsigned long)
MK_NCMP_(slli, long long)
MK_NCMP_(ulli, unsigned long long)
MK_NCMP_(f, float)
MK_NCMP_(d, double)
MK_NCMP_(ld, long double)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66887241

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档