6

将 unsigned short 转换为 char* (即将 25 转换为 '25')将是一种高效、可移植的方法。

我想避免诸如获取 (std::string) 字符串之类的事情。在这种情况下,性能很重要,因为这种转换需要快速且经常发生。

我正在研究诸如使用 sprintf 之类的东西,但想探索任何和所有想法。

4

5 回答 5

6

首先,做对,然后快速做——只有当你可以确定一段代码没有性能时才进行优化。

snprintf()进入缓冲区会做你想做的事。这是最快的解决方案吗?一点也不。但它是最简单的,它足以让你的代码进入工作状态。从那里开始,如果您发现这些调用snprintf()非常费力以至于需要对其进行优化,那么只有在那时才能寻求更快的解决方案。

于 2011-01-18T21:26:32.977 回答
2

一个字符串数组,使得

array[25] = "25";
array[26] = "26";

array[255] = "255";

也许?您可以编写一个很容易为您生成表格源代码的小程序,然后在您的项目中使用该文件。

编辑:我不明白你不想涉及字符串的意思。

于 2011-01-18T21:34:24.780 回答
2

试试这个:

int convert(unsigned short val, char* dest)
{
  int i = 0;
  if (val > 10000)
  {
    dest[i++] = (val / 10000) | 0x30;
    val %= 10000;
  }
  if (val > 1000)
  {
    dest[i++] = (val / 1000) | 0x30;
    val %= 1000;
  }
  if (val > 100)
  {
    dest[i++] = (val / 100) | 0x30;
    val %= 100;
  }
  if (val > 10)
  {
    dest[i++] = (val / 10) | 0x30;
    val %= 10;
  }
  dest[i++] = (val) | 0x30;
  dest[i] = 0;
  return i;
}
于 2011-01-18T22:48:15.343 回答
1

我会说至少尝试 sprintf 并且由于您已将其标记为 C++,因此请尝试StringStream并实际分析它们。在许多情况下,编译器足够聪明,可以构建出运行良好的东西。只有当您知道这将成为瓶颈时,您才需要真正找到更快的方法。

于 2011-01-18T21:29:04.943 回答
1

我在这里对各种功能进行了测试,这就是我想出的:

write_ushort:7.81 s
uShortToStr:8.16 s
转换:6.71 s
use_sprintf:49.66 s

(Write_ushort 是我的版本,我试图尽可能清楚地编写它,而不是微优化,以格式化为给定的字符缓冲区; use_sprintf 是明显的 sprintf(buf, "%d", x) ,仅此而已;其他两个取自此处的其他答案。)

这是他们之间非常惊人的区别,不是吗?谁会想到使用 sprintf 面临几乎一个数量级的差异?哦,是的,我对每个测试的函数迭代了多少次?

// Taken directly from my hacked up test, but should be clear.
// Compiled with gcc 4.4.3 and -O2.  This test is interesting, but not authoritative.
int main() {
  using namespace std;
  char buf[100];

#define G2(NAME,STMT) \
  { \
    clock_t begin = clock(); \
    for (int count = 0; count < 3000; ++count) { \
      for (unsigned x = 0; x <= USHRT_MAX; ++x) { \
        NAME(x, buf, sizeof buf); \
      } \
    } \
    clock_t end = clock(); \
    STMT \
  }
#define G(NAME) G2(NAME,) G2(NAME,cout << #NAME ": " << double(end - begin) / CLOCKS_PER_SEC << " s\n";)
  G(write_ushort)
  G(uShortToStr)
  G(convert)
  G(use_sprintf)
#undef G
#undef G2

  return 0;
}

Sprintf 转换了所有可能的无符号短裤范围,然后在我大约 5 年的旧笔记本电脑上以平均每次转换大约 0.25 µs 的速度再次完成整个范围 2,999 次。

Sprintf 是可移植的;它是否也足以满足您的要求?


我的版本:

// Returns number of non-null bytes written, or would be written.
// If ret is null, does not write anything; otherwise retlen is the length of
// ret, and must include space for the number plus a terminating null.
int write_ushort(unsigned short x, char *ret, int retlen) {
  assert(!ret || retlen >= 1);

  char s[uint_width_10<USHRT_MAX>::value];  // easy implementation agnosticism
  char *n = s;
  if (x == 0) {
    *n++ = '0';
  }
  else while (x != 0) {
    *n++ = '0' + x % 10;
    x /= 10;
  }

  int const digits = n - s;
  if (ret) {
    // not needed by checking retlen and only writing to available space
    //assert(retlen >= digits + 1);

    while (--retlen && n != s) {
      *ret++ = *--n;
    }
    *ret = '\0';
  }
  return digits;
}

编译时日志 TMP 函数并不是什么新鲜事,但包括这个完整的例子,因为它是我使用的:

template<unsigned N>
struct uint_width_10_nonzero {
  enum { value = uint_width_10_nonzero<N/10>::value + 1 };
};
template<>
struct uint_width_10_nonzero<0> {
  enum { value = 0 };
};
template<unsigned N>
struct uint_width_10 {
  enum { value = uint_width_10_nonzero<N>::value };
};
template<>
struct uint_width_10<0> {
  enum { value = 1 };
};
于 2011-01-19T04:03:39.257 回答