是否可依据C++标准安全使用std::string组装二进制数据为消息?
问题
我使用std::string存储从套接字读取的二进制数据,这些数据包含以'$'开头、'#'结尾的消息,每条消息中可能包含'\0'字符。
我通过std::string::find()定位首个消息的位置,并使用std::string::substr()从字符串中提取该消息:
class MessageSplitter { public: MessageSplitter() { m_data.reserve(1'000'000); } void appendBinaryData(const std::string& binaryData) { m_data.append(bytes); } bool popMessage(std::string& msg) { size_t beg_index = m_data.find("$"); if (beg_index == std::string::npos) { return false; } size_t end_index = m_data.find("#", beg_index); if (end_index == std::string::npos) { return false; } size_t count = end_index - beg_index + end.size(); msg = m_data.substr(beg_index, count); m_data = m_data.substr(end_index + end.size()); return true; } private: std::string m_data; };
我通过如下方式从套接字读取数据(省略recv的错误检查):
char buffer[4096]; int ret = ::recv(m_socket, buffer, 4096, 0); std::string binaryData = std::string(buffer, ret);
该方法在Windows上运行正常,但依据C++标准,是否能保证在其他平台也可正常工作?
回答
先纠正你代码里的几个逻辑错误,这些错误和平台无关,但会导致功能失效:
appendBinaryData函数里,你调用了m_data.append(bytes),但参数应该是传入的binaryData,变量名写错了,正确写法是m_data.append(binaryData);popMessage里的end.size()是无意义的,你要取的是结束符#的长度(也就是1),所以count应该是end_index - beg_index + 1,截取剩余数据时应该用m_data.substr(end_index + 1)。
回到核心问题:依据C++标准,用std::string存储包含'\0'的二进制数据是完全合法且跨平台的。
C++标准定义的std::string本质是字节序列的容器,它的长度由内部维护的size()值决定,和序列中是否包含'\0'没有关系。find()、substr()、append()这些成员函数都是基于字节位置和长度进行操作的,不会因为遇到'\0'就停止处理。你用std::string(buffer, ret)构造字符串的方式也是标准允许的,这个构造函数会准确读取ret个字节,不管其中有没有'\0'。
只要修正代码里的变量名和计算错误,这套逻辑在任何符合C++标准的平台上都能正常工作,和Windows、Linux、macOS等平台无关。
内容的提问来源于stack exchange,提问作者Andy
相关产品推荐
相关产品推荐

