如何在处理常规C字符串的C风格函数中有效地使用std :: string?

问题描述:

这是一个古老的问题,我曾经观察过。所以想到一次为所有人澄清一次&。有许多标准/正统的C库函数,只处理C风格的字符串。例如,我当前的实现看起来是这样的:如何在处理常规C字符串的C风格函数中有效地使用std :: string?

std::string TimeStamp (const time_t seconds) // version-1 
{ 
    auto tm = *std::localtime(&seconds); // <ctime> 
    char readable[30] = {}; 
    std::strftime(&readable[0], sizeof(readable) - 1, "%Y-%h-%d %H:%M:%S:", &tm); 
    return readable; 
} 

以上按预期工作。但正如你所看到的那样,readable被从堆栈阵列复制到std::string。现在这个功能非常频繁地被调用,用于记录&其他目的。

因此,我把它转化为以下几点:

std::string TimeStamp (const time_t seconds) // version-2 
{ 
    auto tm = *std::localtime(&seconds); // <ctime> 
    std::string readable(30,0); 
    std::strftime(&readable[0], readable.length(), "%Y-%h-%d %H:%M:%S:", &tm); 
    return readable; 
} 

在单元测试的水平,它显然似乎工作。但是为了在我的更大的代码中进行总体日志记录,它不知何故被搞砸了。此输出后出现一个新行字符&许多输出字符串在此函数外部调用不会被打印。仅当“版本-1”更改为“版本-2”时才会发生此类问题。
即使下面的修改也于事无补:

readable.resize(1 + std::strftime(&readable[0], readable.length(), "%Y-%h-%d %H:%M:%S:", &tm)); 

这有什么错在我的代码?在C风格字符串函数中直接使用std::string的正确方法是什么?

+0

'\ 0'可以出现在'std :: string'中,你必须正确调整字符串的大小。 (我认为'1 +'不正确)。 – Jarod42

+0

@ Jarod42,实际去掉'1+'可以解决问题。但是,我把它作为一种惯例,即一个字符串应该以'NUL'字符结尾。顺便说一句,如果你有一个解释,为什么'1 +'是错误的,它将如何影响输出(由于插件'NUL'),然后随意将其作为答案。谢谢。 – iammilind

+0

你应该检查'strftime'的返回值并且处理失败 –

std::string可以有\0在里面。

所以

std::string s1 = "ab\0\0cd"; // s1 contains "ab"  -> size = 2 
std::string s2{"ab\0\0cd", 6}; // s2 contains "ab\0\0cd" -> size = 6 

你的第一个片段使用构造1,而第二个是类似于第二一个(填充有\0大小30的字符串)。

所以你必须正确调整你的字符串的大小,以避免trailing \0

+0

为什么会有'\ 0'? –

+0

@LightnessRacesinOrbit:OP用较短的缓冲区覆盖大小为“30”的字符串的开头。 – Jarod42

+0

是的,那么为什么会有'\ 0'? –

您的第一个功能是正确的。第二个函数中的麻烦细节毫无意义,因为即使一旦你做对了,第一个函数也没有改进。

事实上,它可能会更糟糕,因为需要过度分配字符串并将其调整大小。例如,或许30的大小超过了小字符串优化的大小,但数据的实际长度却没有。