简体   繁体   English

有效地将unsigned short转换为char *

[英]Efficiently convert an unsigned short to a char*

What would be an efficient, portable way to convert a unsigned short to a char* (ie convert 25 to '25'). 将unsigned short转换为char *(即将25转换为'25')的高效,便携方式是什么。

I'd like to avoid things such as getting (std::string) strings involved. 我想避免使用诸如获取(std :: string)字符串之类的内容。 Performance is important in this case since this conversion will need to happen quickly and often. 在这种情况下,性能很重要,因为这种转换需要快速而且经常发生。

I was looking into things such as using sprintf but would like to explorer any and all ideas. 我正在研究诸如使用sprintf之类的东西,但我想探索任何和所有的想法。

First off, do it right, then do it fast--only optimize if you can see for certain that a piece of code is not performant. 首先,做正确,然后快速执行 - 只有在您可以确定某段代码不具备性能时才进行优化。

snprintf() into a buffer will do what you want. snprintf()进入缓冲区会做你想要的。 Is it the fastest possible solution? 它是最快的解决方案吗? Not at all. 一点也不。 But it is among the simplest, and it will suffice to get your code into a working state. 但它是最简单的,只需将代码置于工作状态即可。 From there, if you see that those calls to snprintf() are so laborious that they need to be optimized, then and only then seek out a faster solution. 从那里,如果你看到那些对snprintf()调用是如此费力以至于需要进行优化, 那么只有找到更快的解决方案。

An array of strings such that 这样的字符串数组

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

array[255] = "255";

maybe? 也许? You could write a small program that generates the table source code for you quite easily, and then use this file in your project. 你可以编写一个很容易为你生成表源代码的小程序,然后在你的项目中使用这个文件。

Edit: I don't get what you mean by you don't want to ge strings involved. 编辑:我不明白你的意思,你不想参与ge字符串。

I would say at least try sprintf and since you have this tagged as C++, try StringStream , and actually profile them. 我会说至少尝试sprintf,因为你有这个标记为C ++,尝试StringStream ,并实际配置它们。 In many cases the compiler is smart enough to build something that works pretty well. 在许多情况下,编译器足够聪明,可以构建非常好用的东西。 Only when you know it's going to be a bottleneck do you need to actually find a faster way. 只有当你知道它将成为瓶颈时,你才需要真正找到一种更快的方法。

try this: 尝试这个:

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;
}

I hacked together a test of various functions here, and this is what I came up with: 我在这里攻击了各种功能的测试,这就是我提出的:

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

(Write_ushort is my version, which I tried to write as clearly as possible, rather than micro-optimize, to format into a given character buffer; use_sprintf is the obvious sprintf(buf, "%d", x) and nothing else; the other two are taken from other answers here.) (Write_ushort是我的版本,我试图尽可能清楚地写,而不是微优化,格式化为给定的字符缓冲区; use_sprintf是显而易见的sprintf(buf,“%d”,x),没有别的;另外两个来自其他答案。)

This is a pretty amazing difference between them, isn't it? 这是他们之间相当惊人的差异,不是吗? Who would ever think to use sprintf faced with almost an order of magnitude difference? 谁会想到使用sprintf面临几乎一个数量级的差异? Oh, yeah, how many times did I iterate each tested function? 哦,是的,我多少次迭代每个测试过的函数?

// 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 converted the entire possible range of unsigned shorts, then did the whole range again 2,999 more times at about 0.25 µs per conversion, on average, on my ~5 year old laptop. Sprintf转换了整个可能的无符号短路范围,然后在我的~5岁笔记本电脑上,平均每次转换大约0.25μs,再次完成整个范围2,999次

Sprintf is portable; Sprintf是便携式的; is it also efficient enough for your requirements? 它是否也足以满足您的要求?


My version: 我的版本:

// 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;
}

Compile-time log TMP functions are nothing new, but including this complete example because it's what I used: 编译时日志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 };
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM