在此之前我已经提到了relevant question和其他帖子。我也知道std::to_string()
是最好的方式(但在少数平台上不可用)。
在试验时,我遇到了memcpy()
的一个奇怪问题。例如,假设我们始终将内置数据类型(int
,char
,long
)传递给以下函数:
template<typename T>
std::string to_string (const T& value)
{
std::string s(16, 0); // Max size captured
::memcpy(&s[0], &value, sizeof(value));
return s;
}
在示例程序中单独运行此函数可以正常工作。但是当插入更大的代码库时,不知何故它会产生奇怪的结果!即它给出虚假的价值。 (Ubuntu 14.10,g ++ 4.9 -std = c ++ 11)
但是,如果我使用sprintf()
转换上述程序,它可以正常工作。
template<typename T>
std::string to_string (const T& value)
{
std::string s(16, 0); // Max size captured
s[::snprintf(&s[0], "%d", value)] = 0;
return s;
}
问题:
memcpy()
的未定义行为(甚至是
sprintf()
)?答案 0 :(得分:2)
回顾一下,是的,您不想使用memcpy()
。使用snprintf()
,您可以避免自己将数字转换为ASCII。这样的事情可能会更好:
template<typename T>
std::string to_string (const T& value)
{
char buf[16];
::snprintf(buf, sizeof(buf), "%d", value);
// ^-- size was missing in your example
return buf;
}
但是,你在这个功能中有很大的流量,因为你不知道T会是什么。它可能是一个双倍,"%d"
将无法正常工作。同样,它可以是一个字符串(char const *
)。
如果要手动将数字转换为ASCII,可以使用循环,如下所示:
template<typename T>
std::string to_string (T value)
{
char buf[16]; // any int number is less than 16 characters
char *s = buf + sizeof(buf);
*--s = '\0';
do
{
*--s = value % 10 + '0'; // conversion to ASCII, 1 digit at a time
value /= 10;
}
while(value > 0);
return s;
}
警告:该功能无法正确处理负数。我会把那个作为练习让你按要求处理。
现在,如果你想使用一种适用于你提到的所有系统的C ++方式,而不使用boost或C ++ 11。
template<typename T>
std::string to_string (T const& value)
{
std::stringstream ss;
ss << value;
return ss.str();
}
在这种情况下,stringstream知道如何处理T,无论T是什么,数字,对象等,只要这些内容理解<<
std::cout << "Hello!" << std::endl;
中的std::ostream& operator << (std::ostream& out, Node const& node);
。
如果你看看我的一个名为as2js的项目,你会看到一个名为include / as2js / node.h的文件,它声明如下:
Node n;
std::out << n << std::endl;
这意味着您可以稍后创建节点并按以下方式打印:
{{1}}
这意味着你的to_string()函数可以用于我的Node对象。
您可以在lib / node_display.cpp
下找到所有这些的实现