C++ c++;函数将时间格式化为std::string:缓冲区长度?

C++ c++;函数将时间格式化为std::string:缓冲区长度?,c++,time,buffer,stdstring,strftime,C++,Time,Buffer,Stdstring,Strftime,我想要一个函数,它将接受一个time\t参数和一个任意格式的字符串并格式化它。我想要这样的东西: std::string GetTimeAsString(std::string formatString, time_t theTime) { struct tm *timeinfo; timeinfo = localtime( &theTime); char buffer[100]; strftime(buffer, 100, formatString.c

我想要一个函数,它将接受一个time\t参数和一个任意格式的字符串并格式化它。我想要这样的东西:

std::string GetTimeAsString(std::string formatString, time_t theTime)
{
    struct tm *timeinfo;
    timeinfo = localtime( &theTime);

    char buffer[100];
    strftime(buffer, 100, formatString.c_str(), timeinfo);
    std::string result(buffer);
    return result;
}
然而,我遇到的一个问题是缓冲区长度。我正在考虑使用formatString*4作为缓冲区长度。但我猜你不能动态设置缓冲区长度?也许我可以选择一个任意大的缓冲区?我有点被困在如何使它通用的问题上


如何编写函数来实现这一点?

使用
向量作为缓冲区,而不是数组。反复增加大小,直到strftime返回非零。

我认为最好的办法是提供一个可能处理绝大多数情况的固定缓冲区,然后对其余情况进行特殊处理。类似于(未经测试,但在我头骨内的湿器中除外):

如果提供的缓冲区不够大,
strftime
将返回零。在这种情况下,您将开始分配更大的缓冲区,直到合适为止

您的未分配缓冲区大小和用于分配大小的增量可以根据您的需要进行调整。这种方法的优点是,除了极少数情况外,您不会注意到效率受到的影响(无论多么小),绝大多数情况下不会进行分配

此外,还可以选择其他方法(例如+10%,加倍等)来增加缓冲区大小。

如果缓冲区大小太小而无法容纳预期结果,strftime()函数将返回0。使用此属性,您可以在堆上分配缓冲区,并尝试使用2的连续幂作为其大小:1、2、4、8、16等,直到缓冲区足够大。使用2的幂的优点是,解的复杂度与结果的长度成对数比例

还有一种特殊情况需要考虑:格式可能是这样的,结果的大小将始终为0(例如,空格式)。不确定如何处理此问题。

如果您有C++11:

std::string GetTimeAsString(std::string formatString, time_t theTime)
{
    struct tm *timeinfo;
    timeinfo = localtime( &theTime);

    formatString += '\a'; //force at least one character in the result
    std::string buffer;
    buffer.resize(formatstring.size());
    int len = strftime(&buffer[0], buffer.size(), formatString.c_str(), timeinfo);
    while (len == 0) {
        buffer.resize(buffer.size()*2);
        len = strftime(&buffer[0], buffer.size(), formatString.c_str(), timeinfo);
    } 
    buffer.resize(len-1); //remove that trailing '\a'
    return buffer;
}

注意:我将formatString作为常量引用(为了速度和安全),并使用结果字符串作为缓冲区,这比以后进行额外复制要快。我也会从与formatstring相同的大小开始,每次尝试都会将大小增加一倍,但这很容易更改为更适合strftime结果的大小。

C++11解决方案with
std::put_time()

std::string GetTimeAsString(std::string formatString,time\u t the time)
{
struct tm*timeinfo=localtime(&theTime);
std::ostringstream os;

os或者,因为他返回字符串,所以使用字符串作为缓冲区。只有当你有C++11,@Mooing.True时,它才在C++11中有效。否则vector是更好的选择。或者,因为他返回字符串,所以使用字符串作为缓冲区。没有速度惩罚,代码更小。这真的合法吗?我只是问,因为我最近不得不投资tigate
oper[]
并使用-这表示“返回的数组指向不应在程序中直接修改的内部位置”。@Paxdiablo:For
data
这是正确的。但是,在C++11:§21.4.1/5
中,对于任何基本的字符串对象,标识&*(s.begin()+n)==&*s.begin+n应适用于n的所有值,因此只要格式化字符串实际包含字符,0就可以正常工作。不幸的是,某些格式参数(例如
%p
)可能会产生空字符串(取决于区域设置)这与错误无法区分,在这种情况下,您将得到一个无限循环。到目前为止,我找到的唯一解决方法是在格式字符串的末尾添加一个任意字符(例如空格)它允许区分空结果和错误,并在返回字符串之前删除该错误字符。@syam:cplusplus和cppreference在返回类型上不一致。因为cppreference在历史上更准确,我相信你。修复了。(从技术上讲,这不会是一个无限循环,它会抛出
std::bad_alloc
,但你的观点是正确的)@MooingDuck好吧,我没有检查任何一个网站,老实说,我是从
man 3 strftime
得到的,这也是一个相当安全的赌注。;)至于无限循环,我的措辞确实是错误的。
std::string GetTimeAsString(std::string formatString, time_t theTime)
{
    struct tm *timeinfo;
    timeinfo = localtime( &theTime);

    formatString += '\a'; //force at least one character in the result
    std::string buffer;
    buffer.resize(formatstring.size());
    int len = strftime(&buffer[0], buffer.size(), formatString.c_str(), timeinfo);
    while (len == 0) {
        buffer.resize(buffer.size()*2);
        len = strftime(&buffer[0], buffer.size(), formatString.c_str(), timeinfo);
    } 
    buffer.resize(len-1); //remove that trailing '\a'
    return buffer;
}
std::string GetTimeAsString(std::string formatString, time_t theTime)
{
    struct tm* timeinfo = localtime(&theTime);

    std::ostringstream os;
    os << std::put_time(timeinfo, formatString.c_str());
    return os.str();
}