Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何以优雅高效的方式将无符号/有符号整数/长字符串转换为C字符串?_C++_C++11_G++ - Fatal编程技术网

C++ 如何以优雅高效的方式将无符号/有符号整数/长字符串转换为C字符串?

C++ 如何以优雅高效的方式将无符号/有符号整数/长字符串转换为C字符串?,c++,c++11,g++,C++,C++11,G++,这里有很多人问过如何将无符号/有符号整数/长字符串转换为C字符串 最常见的答案是使用sprintf(或snprintf)。但是,它需要不同类型的不同格式字符串(例如uint32\u t、int32\u t、uint64\u t、int64\u t等) 我有这样一个函数模板: // T can only be uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t template <type T> void foo(char*

这里有很多人问过如何将无符号/有符号整数/长字符串转换为C字符串

最常见的答案是使用sprintf(或snprintf)。但是,它需要不同类型的不同格式字符串(例如uint32\u t、int32\u t、uint64\u t、int64\u t等)

我有这样一个函数模板:

// T can only be uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t
template <type T>
void foo(char* buffer, T value) {
// write value to buffer
}
//T只能是uint16\u T、int16\u T、uint32\u T、uint64\u T
模板
void foo(字符*缓冲区,T值){
//将值写入缓冲区
}
我可以专门化函数模板来解决我的问题

我只是想知道是否有一种更优雅、更高效的方法(即没有像stringstream这样的临时缓冲区)


谢谢

C++17之前最简单的实现可能是:

std::strcpy(buffer, std::to_string(value).c_str());
这确实需要一个临时缓冲区(一个临时的
std::string
),但我会犹豫是否过早地进行优化。在我看来,这将是最优雅的转换方式——它简单易懂

(请注意,函数签名不可能确保
缓冲区
指针指向足以容纳字符串化值的分配。)

在C++17中,您可以直接使用(您必须自己使用此函数添加null终止字符;文档中没有说明它为您添加了一个)


也许有一个中间地带,您可以声明一个trait来获取每个数字类型的printf样式格式说明符

#include <cstdio>

template <typename T>
struct printf_specifier
{
    static char const * const value;
};

template<> char const * const printf_specifier<char>::value = "%hhd";
template<> char const * const printf_specifier<unsigned char>::value = "%hhu";
template<> char const * const printf_specifier<short>::value = "%hd";
template<> char const * const printf_specifier<unsigned short>::value = "%hu";
template<> char const * const printf_specifier<int>::value = "%d";
template<> char const * const printf_specifier<unsigned int>::value = "%u";
template<> char const * const printf_specifier<long>::value = "%ld";
template<> char const * const printf_specifier<unsigned long>::value = "%lu";
template<> char const * const printf_specifier<long long>::value = "%lld";
template<> char const * const printf_specifier<unsigned long long>::value = "%llu";
template<> char const * const printf_specifier<float>::value = "%f";
template<> char const * const printf_specifier<double>::value = "%f";

template <typename T>
void foo(char *buffer, T value)
{
    std::sprintf(buffer, printf_specifier<T>::value, value);
}

如果即使这样也太膨胀,您也可以完全自己进行转换:

#include <algorithm>
#include <cstdlib>

template <typename T>
void foo(char *buffer, T value)
{
    static_assert(std::is_integral<T>::value, "Type of value must be an integral type");

    if (value < 0) {
        *(buffer++) = '-';
    }

    char *start = buffer;

    while (value != 0) {
        *(buffer++) = '0' + std::abs(value % 10);
        value /= 10;
    }

    if (buffer == start) {
        *(buffer++) = '0';
    } else {
        std::reverse(start, buffer);
    }

    *buffer = '\0';
}
#包括
#包括
模板
void foo(字符*缓冲区,T值)
{
静态_断言(std::is_integral::value,“值的类型必须是整数类型”);
如果(值<0){
*(buffer++)='-';
}
char*start=buffer;
while(值!=0){
*(buffer++)=“0”+std::abs(值%10);
数值/=10;
}
如果(缓冲区==开始){
*(缓冲区++)=“0”;
}否则{
标准::反向(启动、缓冲);
}
*缓冲区='\0';
}

使用log10计算字符串的长度并从后向前写入可能会更快,而不是向后写入然后反转,但是如果您认为有必要,我将把这个选项留给您作为练习。

也许C++17之前最简单的实现是:

std::strcpy(buffer, std::to_string(value).c_str());
这确实需要一个临时缓冲区(一个临时的
std::string
),但我会犹豫是否过早地进行优化。在我看来,这将是最优雅的转换方式——它简单易懂

(请注意,函数签名不可能确保
缓冲区
指针指向足以容纳字符串化值的分配。)

在C++17中,您可以直接使用(您必须自己使用此函数添加null终止字符;文档中没有说明它为您添加了一个)


也许有一个中间地带,您可以声明一个trait来获取每个数字类型的printf样式格式说明符

#include <cstdio>

template <typename T>
struct printf_specifier
{
    static char const * const value;
};

template<> char const * const printf_specifier<char>::value = "%hhd";
template<> char const * const printf_specifier<unsigned char>::value = "%hhu";
template<> char const * const printf_specifier<short>::value = "%hd";
template<> char const * const printf_specifier<unsigned short>::value = "%hu";
template<> char const * const printf_specifier<int>::value = "%d";
template<> char const * const printf_specifier<unsigned int>::value = "%u";
template<> char const * const printf_specifier<long>::value = "%ld";
template<> char const * const printf_specifier<unsigned long>::value = "%lu";
template<> char const * const printf_specifier<long long>::value = "%lld";
template<> char const * const printf_specifier<unsigned long long>::value = "%llu";
template<> char const * const printf_specifier<float>::value = "%f";
template<> char const * const printf_specifier<double>::value = "%f";

template <typename T>
void foo(char *buffer, T value)
{
    std::sprintf(buffer, printf_specifier<T>::value, value);
}

如果即使这样也太膨胀,您也可以完全自己进行转换:

#include <algorithm>
#include <cstdlib>

template <typename T>
void foo(char *buffer, T value)
{
    static_assert(std::is_integral<T>::value, "Type of value must be an integral type");

    if (value < 0) {
        *(buffer++) = '-';
    }

    char *start = buffer;

    while (value != 0) {
        *(buffer++) = '0' + std::abs(value % 10);
        value /= 10;
    }

    if (buffer == start) {
        *(buffer++) = '0';
    } else {
        std::reverse(start, buffer);
    }

    *buffer = '\0';
}
#包括
#包括
模板
void foo(字符*缓冲区,T值)
{
静态_断言(std::is_integral::value,“值的类型必须是整数类型”);
如果(值<0){
*(buffer++)='-';
}
char*start=buffer;
while(值!=0){
*(buffer++)=“0”+std::abs(值%10);
数值/=10;
}
如果(缓冲区==开始){
*(缓冲区++)=“0”;
}否则{
标准::反向(启动、缓冲);
}
*缓冲区='\0';
}
使用log10计算字符串的长度并从后向前写入可能会更快,而不是将其向后写入然后反转,但如果您认为有必要,我会将该选项留给您作为练习。

只需使用或:

并将结果复制到新的std::string

这里有一些可以很好地优化的东西。与常规itoa不同的是,它的整数除法减少了两倍,而在大多数CPU上,整数除法并不是简单的指令

static int log10_1(unsigned int num)
{
    int ret;
    static_assert(sizeof(num) == 4, "expected 32-bit unsigned int");
    // extend this logic for 64 bit numbers
    if (num >= 10000)
    {
        if (num >= 1000000)
        {
            if (num >= 100000000)
                ret = (num >= 1000000000) ? 10 : 9;
            else
                ret = (num >= 10000000) ? 8 : 7;
        }
        else
            ret = (num >= 100000) ? 6 : 5;
    }
    else
    {
        if (num >= 100)
            ret = num >= 1000 ? 4 : 3;
        else
            ret = num >= 10 ? 2 : 1;
    }
    return ret;
}

// write string representation of number `n` into buf and return pointer to rterminating null
char* to_str(char* buf, unsigned int n)
{
    static const char dig_[] = "0001020304050607080910111213141516171819"
        "20212223242526272829303132333435363738394041424344454647484950515253545556575859"
        "60616263646566676869707172737475767778798081828384858687888990919293949596979899";
    int len = log10_1(n);
    char *p = buf + len;
    *p-- = 0;
    while (n >= 100)
    {
        unsigned int x = (n % 100) * 2;
        n /= 100;
        *p-- = dig_[x + 1];
        *p-- = dig_[x];
    }
    if (n >= 10)
    {
        unsigned int x = n * 2;
        *p-- = dig_[x + 1];
        *p-- = dig_[x];
    }
    else
        *p-- = (char)('0' + n);
    return buf + len;
}

// write string representation of number `n` into buf and return pointer to terminating null
char* to_str(char* buf, int n)
{
    unsigned int l;
    if (n < 0)
    {
        *buf++ = '-';
        if (n == INT_MIN)
        {
            static_assert(sizeof(n) == 4, "expected 32-bit int");
            memcpy(buf, "2147483648", 10);
            return buf + 10;
        }
        l = (unsigned int)(-n);
    }
    else
        l = (unsigned int)n;
    return to_str(buf, l);
}
对于优化到的字符串函数,已经有一个良好的stackoverflow页:。最快的算法与我的基本相同。

只需使用或:

并将结果复制到新的std::string

这里有一些可以很好地优化的东西。与常规itoa不同的是,它的整数除法减少了两倍,而在大多数CPU上,整数除法并不是简单的指令

static int log10_1(unsigned int num)
{
    int ret;
    static_assert(sizeof(num) == 4, "expected 32-bit unsigned int");
    // extend this logic for 64 bit numbers
    if (num >= 10000)
    {
        if (num >= 1000000)
        {
            if (num >= 100000000)
                ret = (num >= 1000000000) ? 10 : 9;
            else
                ret = (num >= 10000000) ? 8 : 7;
        }
        else
            ret = (num >= 100000) ? 6 : 5;
    }
    else
    {
        if (num >= 100)
            ret = num >= 1000 ? 4 : 3;
        else
            ret = num >= 10 ? 2 : 1;
    }
    return ret;
}

// write string representation of number `n` into buf and return pointer to rterminating null
char* to_str(char* buf, unsigned int n)
{
    static const char dig_[] = "0001020304050607080910111213141516171819"
        "20212223242526272829303132333435363738394041424344454647484950515253545556575859"
        "60616263646566676869707172737475767778798081828384858687888990919293949596979899";
    int len = log10_1(n);
    char *p = buf + len;
    *p-- = 0;
    while (n >= 100)
    {
        unsigned int x = (n % 100) * 2;
        n /= 100;
        *p-- = dig_[x + 1];
        *p-- = dig_[x];
    }
    if (n >= 10)
    {
        unsigned int x = n * 2;
        *p-- = dig_[x + 1];
        *p-- = dig_[x];
    }
    else
        *p-- = (char)('0' + n);
    return buf + len;
}

// write string representation of number `n` into buf and return pointer to terminating null
char* to_str(char* buf, int n)
{
    unsigned int l;
    if (n < 0)
    {
        *buf++ = '-';
        if (n == INT_MIN)
        {
            static_assert(sizeof(n) == 4, "expected 32-bit int");
            memcpy(buf, "2147483648", 10);
            return buf + 10;
        }
        l = (unsigned int)(-n);
    }
    else
        l = (unsigned int)n;
    return to_str(buf, l);
}

对于优化到的字符串函数,已经有一个良好的stackoverflow页:。最快的算法与我的基本相同。

感谢您的快速回复。同意避免所有过早的优化。但它在我的应用程序的关键路径上(要求非常快…<2微秒…,所以一切都很重要)。因此,我想看看其他人将如何实现:)不幸的是,我仅限于GCC 4.8.x,它甚至没有实现完整的C++11(尽管我在这里放了一个C++11标记)。@Hei我添加了一种可能对您有用的方法。@cdhowie这就是MS std::to_字符串的实现方式(AFAIK)@嗨,如果你担心你的关键路径,我建议你避免使用snprintf/printf。它将大量代码加载到指令缓存中,这会影响延迟。如果您的应用程序对损失100纳秒很敏感,您可能需要测量并比较自己的时间。特别是如果你只需要转换整数。谢谢你的快速回复。同意避免所有过早的优化。但它在我的应用程序的关键路径上(要求非常快…<2微秒…,所以一切都很重要)。所以我想看看其他人将如何实现:)不幸的是,我仅限于GCC4.8.x,它甚至没有实现完整的C++11(尽管