为什么std :: string使wsagetlasterror返回零
Why std::string makes WSAGetLastError returning zero?
有一天。我写了插座包装班,例如C 的python内置插座库(Visual Studio 2015(
所有功能的运作良好。但是,我发现我所做的一些功能有问题。
使用std::string
的方法之后,例如.size()
,.clear()
,WSAGetLastError()
总是返回零。
std::string str = "Hello, world";
size_t recvsz = ::send(socket, str.c_str(), str.size(), 0);
// Why always return zero after using std::string's methods?
int err = ::WSAGetLastError();
因此,我不知道插座状态,插座已经死了,或者插座仍在等待接收数据。
所以,我使用了一种方法,在std::string
的方法之前存储WSAGetLastError()
返回值,然后使用WSASetLastError()
恢复它。
std::string str = "Hello, world";
// Before using std::string's methods
int err = ::WSAGetLastError();
size_t recvsz = ::send(socket, str.c_str(), str.size(), 0);
// Restore error value after std::string's methods
::WSASetLastError(err);
我使用的正确方法是正确的吗?或为什么std::string
犯下最后一次错误?
编辑:哇...我错误.. :(。
SOCKET socket;
char buf[100] = {0x00,};
std::string data, temp_buf;
ssize_t recvsz = ::recv(socket, buf, 99, 0);
// When err has proper error code before std::string methods
// It just for a test
// int err = ::WSAGetLastError();
temp_buf = buf;
data += buf;
int err = WSAGetLastError(); // Always return zero!
,因为您通过写入不拥有的只读记忆来犯下了总体而言。简而言之,您将计算机的内存打电话给现在,现在您的程序将无法预测。
使用合规的C 11编译器,您可以做:
ssize_t recvsz = ::recv(socket, &str[0], str.size(), 0);
那是因为&str[0]
是指向实际的字符串缓冲区的指针(在非const
上下文中(,并且是因为从C 11中保证了数据可以存储连续。从技术上讲,在此之前,不是很多(尽管实际上它基本上总是是(。
否则,您将不得不分配自己的char[]
缓冲区,以接收数据。除非您使用具有紧密资源限制的嵌入式系统,否则您可以将其自动存储持续时间几乎没有成本(但无论如何您都不会使用string
(。
顺便说一下,请小心您的返回类型:size_t
未签名。recv
返回a ssize_t
,该签署,可能是否定的,以指示错误条件。
const size_t BUF_SIZE = 256;
char buf[BUF_SIZE];
ssize_t recvsz = ::recv(socket, &buf[0], BUF_SIZE, 0);
if (recvsz < 0) {
// ... handling
}
// Now, optionally:
std::string str(buf, recvsz);
现在,有了所有固定的,答案是即使成功的操作也可以更改"最后一个错误"。因此,是的,如果要保留它,则必须保存,然后重新设置先前的"最后一个错误"值。这确实具有可疑的价值&mdash;为什么您不处理生成的错误?在造成错误后继续进行业务似乎是一种不好的方法。
您不应以这种方式写入std::string
的内部缓冲区。它由对象管理,您必须使用append()
或assign()
之类的功能进行更新,因此字符串可以跟踪其当前内容和长度。
此外,c_str()
返回const char*
指针,您不能写入此类内存。
如果您确定,您将始终编写正确的字节(因此书面数据和内部存储的实际数据长度将匹配(,您可以使用operator[]
来获取对该特定字符的引用字符串(大概是您的情况下的第一个(,并将其地址用作目标缓冲区。
@andyg在他的评论中注意到,C 17引入了std::basic_string::data()
,它也将指针返回到实际的缓冲区。
您的代码应采用以下表格之一:
size_t recvsz = ::recv(socket, &str[0], str.size(), 0);
size_t recvsz = ::recv(socket, str.data(), str.size(), 0); // C++ 17, str must not be const
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- 什么时候在C++中返回常量引用是个好主意
- 你能重载对象变量名本身返回的内容吗
- 为什么 Serial.println(<char[]>);返回随机字符?
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 如何获取std::result_of函数的返回类型
- QueryWorkingSet总是返回false
- (C++)分析树以计算返回错误值的简单算术表达式
- 访问者访问变体并返回不同类型时出错
- 如何返回一个类的两个对象相加的结果
- OpenInventor从9.8升级到10.4.2后,GLSL纹理返回零
- lower_bound()返回最后一个元素
- "throw expression code" 1e7 >返回 d 是什么?投掷标准::overflow_error( "too big" ) : d;意味 着?
- 奇怪的(对我来说)返回声明 - 在谷歌上找不到任何关于它的信息
- 如何取消对nullptr的屏蔽,返回正确的对象
- 奇怪的结构&GCC&clang(void*返回类型)
- 架构决策:返回std::future还是提供回调
- 从python中调用C++函数并获取返回值
- 矩阵向量乘法(cublasDgemv)返回零
- 为什么模板类中的对象不能返回值