在使用libcurl
的过程中,按照教程使用string
类型进行数据接收:
1 2 3 4 5 6
| size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp) { auto sz = size * nmemb; ((string*)userp)->append((char*)buffer, 0, sz); return sz; }
|
但是在测试过程中,接收图片时却总是出现问题,收到的数据远小于原始数据。
于是编写测试代码:
1 2 3 4 5 6 7 8
| void test_append() { char buff[1024]; for(int i = 0; i < 1024; ++i) buff[i] = rand() % 256; cout << "append(n) : " << string().append(buff, 1024).size() << endl; cout << "append(p, n): " << string().append(buff, 0, 1024).size() << endl; }
|
得到输出:
1 2
| append(n) : 1024 append(p, n): 131
|
调试发现,buff[131]
为0。
进一步编写测试:
1 2 3 4 5 6 7 8 9
| void test_append() { const char* str = "0\000123456789"; const int sz = 12; cout << "append(n) : " << string().append(str, sz).size() << endl; cout << "append(p, n): " << string().append(str, 0, sz).size() << endl; cout << "append(s, n): " << string().append(string(str, sz)).size() << endl; cout << "append(s) : " << string().append(string(str)).size() << endl; }
|
得到输出:
1 2 3 4
| append(n) : 12 append(p, n): 1 append(s, n): 12 append(s) : 1
|
那么可以大致猜测,调用append(str, 0, sz)
和string(str)
时,将str
作为\0
结尾的字符串进行了截断。
翻看头文件进行验证。
首先是调用string().append(buff, 1024)
时,实际上是调用了这个函数:
1 2 3 4 5 6
| basic_string& append(const _CharT* __s, size_type __n) { __glibcxx_requires_string_len(__s, __n); _M_check_length(size_type(0), __n, "basic_string::append"); return _M_append(__s, __n); }
|
而调用string().append(buff, 0, 1024)
时,则是调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| basic_string& append(const basic_string& __str, size_type __pos, size_type __n = npos) { return _M_append(__str._M_data() + __str._M_check(__pos, "basic_string::append"), __str._M_limit(__pos, __n)); } size_type _M_check(size_type __pos, const char* __s) const { if (__pos > this->size()) __throw_out_of_range_fmt(__N("%s: __pos (which is %zu) > " "this->size() (which is %zu)"), __s, __pos, this->size()); return __pos; } size_type _M_limit(size_type __pos, size_type __off) const _GLIBCXX_NOEXCEPT { const bool __testoff = __off < this->size() - __pos; return __testoff ? __off : this->size() - __pos; }
|
可以注意到,这里原本const char*
的实参实际上是对应了const basic_string& __str
,也就是说,先调用了string(str)
构造了一个临时的string
对象。数据就是在这里被截断的。
string(const char*)
的源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| basic_string(const _CharT* __s, const _Alloc& __a = _Alloc()) : _M_dataplus(_M_local_data(), __a) { _M_construct(__s, __s ? __s + traits_type::length(__s) : __s+npos); }
template<typename _CharT, typename _Traits, typename _Alloc> void basic_string<_CharT, _Traits, _Alloc>::_M_construct(size_type __n, _CharT __c) { if (__n > size_type(_S_local_capacity)) { _M_data(_M_create(__n, size_type(0))); _M_capacity(__n); }
if (__n) this->_S_assign(_M_data(), __n, __c);
_M_set_length(__n); }
|
如果不是遇到问题,平时还真不一定能注意到这些细节。总之,多学习多记录吧。
最后,我的测试环境如下:
1 2 3 4 5
| [spes@Gensoukyo bin]$ g++ --version g++ (GCC) 10.1.0 Copyright © 2020 Free Software Foundation, Inc. 本程序是自由软件;请参看源代码的版权声明。本软件没有任何担保; 包括没有适销性和某一专用目的下的适用性担保。
|