在没有errno的情况下实现strtol()更好吗?

时间:2018-12-09 05:30:11

标签: c linux string strtol

传统的strtol()通常是这样使用的:

int main()
{
    errno = 0;
    char *s = "12345678912345678900";
    char *endptr;
    long i = strtol(s,  &endptr, 10);
    if(i == LONG_MAX && errno == ERANGE) 
        printf("overflow");
}

我们需要访问errno两次,errno如今通常是一个C宏,最终扩展为一个函数。考虑到将字符串解析为整数并不是一件繁重的工作,这似乎有点昂贵。

那么,在没有strtol的情况下实现errno更好,但使用其他一些方法来指示溢出是否更好呢?

喜欢:

long strtol(const char *nptr, char **endptr, int base, bool *is_overflow);

代替

long strtol(const char *nptr, char **endptr, int base);

2 个答案:

答案 0 :(得分:4)

  

在没有errno的情况下实现strtol更好吗...

否。

  

...但是使用其他方法来指示溢出吗?

否。

long int strtol(const char * restrict nptr, char ** restrict endptr, int base);

strtol()是标准的C库函数,任何实现都必须遵守3个输入的正确使用,并且必须遵守errno


当然,OP可以根据需要实现其他一些my_strtol()

关于避免errno的任何性能问题都是微优化但也是合理的设计目标。

这实际上取决于如何将 string 问题传达给long

  • 溢出"12345678912345678901234567890"

  • 没有转化"abc"

  • 多余的垃圾"123 abc"

  • 允许前导空间,允许尾随空间吗?

  • 允许使用各种基础吗?

一旦定义了所有特殊情况的功能,而不仅仅是溢出,那么即使不大可能进行有意义的性能改进,对errno的编码问题也很有用。

IMO,仅编码为一个基数可能比errno更有效地提高速度。


OP代码不是健壮的strtol()用法。建议:

char *s = "12345678912345678900";

char *endptr;
errno = 0;
long i = strtol(s,  &endptr, 10);
if (errno == ERANGE) printf("Overflow %ld\n", i);
else if (s == endptr) printf("No conversion %ld\n", i);
else if (*endptr) printf("Extra Junk %ld\n", i);
else printf("Success %ld\n", i);

答案 1 :(得分:0)

除了errno中的strtol()之外,实际上还有一些开销,例如跳过空格,照顾底数(10或六),检查字符...

特定环境中,速度是至关重要的,并且您知道所提供的字符串是以10为底的数字,它适合long,您可以将自己的快捷功能,例如

#include <ctype.h>

long mystrtol(char *s) {
   long res = 0, minus = *s == '-';
   if (minus || *s == '+') s++;

   while (isdigit(*s)) {
      res = res*10 + (*s++ - '0');
   }

   return minus ? -res : res;
}

,然后选择内联。