asio::buffer_cast strange output - c++

I am learning boost::asio, and encountered a problem. Basically, asio::buffer_cast() works strange on my machine. Any help would be greatly appreciated.
I have sample code as follows,
#include <iostream>
#include <vector>
#include <sstream>
#include <iomanip>
#include <boost/asio.hpp>
int main ()
{
std::ostringstream type_stream;
type_stream << std::setw(4) << 100;
std::cout<<"type_stream:"<<type_stream.str()<<std::endl;
std::ostringstream head_stream;
head_stream << std::setw(10) << 92;
std::cout<<"head_stream:"<<head_stream.str()<<std::endl;
std::vector<boost::asio::const_buffer> buffers;
buffers.push_back(boost::asio::buffer(type_stream.str()));
buffers.push_back(boost::asio::buffer(head_stream.str()));
auto test = buffers[0];
const unsigned char* p1 = boost::asio::buffer_cast<const unsigned char*>(test);
std::cout<<"type_stream again:"<<std::string(reinterpret_cast<const char*>(p1))<<std::endl;
auto test2 = buffers[1];
const unsigned char* p2 = boost::asio::buffer_cast<const unsigned char*>(test2);
std::cout<<"head_stream again:"<<std::string(reinterpret_cast<const char*>(p2))<<std::endl;
return 0;
}
If you run this code here: https://wandbox.org/permlink/4VkxJ4TFgjHzrath, it works fine. The output is
type_stream: 100
head_stream: 92
type_stream again: 100
head_stream again: 92
But when put the code in a function and run on my machine, I got output as
type_stream: 100
head_stream: 92
type_stream again: 92
head_stream again: 92
Am I doing anything wrong in the code? It seems on my machine the second buffer covered the first one. I have gcc (Ubuntu 7.2.0-8ubuntu3.2) 7.2.0, and the newest boost::asio.

Yes, there's Undefined Behaviour.
The problem is that
buffers.push_back(boost::asio::buffer(type_stream.str()));
the type_stream.str() returns a temporary std::string and therefore the buffer isn't valid after the push.
Fix:
Live On Coliru
#include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <vector>
std::string format_buf(int v, int width) {
std::ostringstream oss;
oss << std::setw(width) << v;
return oss.str();
}
int main() {
std::string type_str = format_buf(100, 4);
std::string head_str = format_buf(92, 10);
std::cout << "type_stream first: " << std::quoted(type_str) << std::endl;
std::cout << "head_stream first: " << std::quoted(head_str) << std::endl;
std::vector<boost::asio::const_buffer> buffers;
buffers.push_back(boost::asio::buffer(type_str));
buffers.push_back(boost::asio::buffer(head_str));
auto test = buffers[0];
const unsigned char *p1 = boost::asio::buffer_cast<const unsigned char *>(test);
std::cout << "type_stream again:" << std::quoted(reinterpret_cast<const char *>(p1)) << std::endl;
auto test2 = buffers[1];
const unsigned char *p2 = boost::asio::buffer_cast<const unsigned char *>(test2);
std::cout << "head_stream again:" << std::quoted(reinterpret_cast<const char *>(p2)) << std::endl;
}
Prints
type_stream first: " 100"
head_stream first: " 92"
type_stream again:" 100"
head_stream again:" 92"
BONUS
Since you're effectively trying to do fixed-width formatting (?) why not make it simpler and more robust:
Live On Coliru
char type[4] = {};
char head[10] = {};
bio::stream<bio::array_sink> tstream(type);
tstream << 100;
bio::stream<bio::array_sink> hstream(head);
hstream << 92;
It's more robust because with your code the fields may be too wide (e.g. with type containing 12345)

With help from #sehe, the following code works. But I got new worries. Is it okay to create char type[4] = {}; char head[10] = {}; char type2[2] = {}; inside prepareBuffers() function? As the buffer was created by buffers.push_back(boost::asio::buffer(type));, I suspect type will be destroyed when goes out of prepareBuffers() function. But the in the main() the program still can access the content of buffer. Is there any copy happens?
#include <boost/asio.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <vector>
namespace bio = boost::iostreams;
void prepareBuffers(std::vector<boost::asio::const_buffer> & buffers){
char type[4] = {};
char head[10] = {};
bio::stream<bio::array_sink> tstream(type);
bio::stream<bio::array_sink> hstream(head);
tstream << 555555;
hstream << 923;
std::cout << "type_stream first: " << std::quoted(type) << std::endl;
std::cout << "head_stream first: " << std::quoted(head) << std::endl;
buffers.push_back(boost::asio::buffer(type));
buffers.push_back(boost::asio::buffer(head));
auto test = buffers[0];
const unsigned char* p1 = boost::asio::buffer_cast<const unsigned char*>(test);
std::cout<<"in function type_stream again:"<<std::string(reinterpret_cast<const char*>(p1))<<std::endl;
test = buffers[1];
const unsigned char* p2 = boost::asio::buffer_cast<const unsigned char*>(test);
std::cout<<"in function head_stream again:"<<std::string(reinterpret_cast<const char*>(p2))<<std::endl;
}
int main() {
std::vector<boost::asio::const_buffer> buffers2;
prepareBuffers(buffers2);
auto test21 = buffers2[0];
const unsigned char* p1 = boost::asio::buffer_cast<const unsigned char*>(test21);
std::cout<<"type_stream again:"<<std::string(reinterpret_cast<const char*>(p1))<<std::endl;
auto test22 = buffers2[1];
const unsigned char* p2 = boost::asio::buffer_cast<const unsigned char*>(test22);
std::cout<<"type_stream again:"<<std::string(reinterpret_cast<const char*>(p2))<<std::endl;
return 0;
}

Related

Whats the error in it. string assignment

I would like to take the data from the struct elements to the internal elements.
What will be a better way to do it.
It shows error: invalid array assignmen berror: invalid array ssignment
error: invalid array assignment error: ‘strcpy’ was not declared in this scope.
#include <iostream>
#include <string>
using namespace std;
struct A
{
char Ip[16];
char port[6];
char sessionkey[32];
}
int main()
{
char m_ip[16];
char m_port[6];
char m_sessionkey[32];
A a;
a.Ip = "10.43.160.94111";
a.port = "12345";
a.sessionkey = "12Abcd12345Abcd12345Abcd1234512";
strcpy(m_ip,a.Ip);
strcpy(m_port,a.port);
strcpy(m_sessionkey,a.sessionkey);
cout << "m_ip:" << m_ip << endl;
cout << "m_port:" << m_port << endl;
cout << "m_sessionkey:" << m_sessionkey << endl;
}
I think you mean the following (C string functions are declared in header <cstring>)
#include <cstring>
//...
char m_ip[16];
char m_port[6];
char m_sessionkey[32];
A a = { "10.43.160.94111", "12345", "12Abcd12345Abcd12345Abcd1234512" };
std::strcpy(m_ip,a.Ip);
std::strcpy(m_port,a.port);
std::strcpy(m_sessionkey,a.sessionkey);
Or instead of
A a = { "10.43.160.94111", "12345", "12Abcd12345Abcd12345Abcd1234512" };
you could write
A a;
a = { "10.43.160.94111", "12345", "12Abcd12345Abcd12345Abcd1234512" };
provided that your compiler supports C++ 2011.
Take into account that you forgot to place a semicol after the closing brace in the structure definition
struct A
{
//...
};
^^^
EDIT: After you unexpectedly changed your code I'd like to point out that this code snippet
A a;
string p = "10.43.160.94111";
string q = "12345";
string r = "12Abcd12345Abcd12345Abcd1234512";
p.copy(a.Ip,16,0);
q.copy(a.port,6,0);
r.copy(a.sessionkey,32,0);
does not make sense. There is no sense to introduce objects of type std::string only that to initialize an object of type struct A.
Another thing you could initially define the structure the following way
struct A
{
std::string Ip;
std::string port;
std::string sessionkey;
};
For writing in C++ prefer to use std::string instead of char * or char[].
A number of your issues will not longer exist if you use std::string instead.
Example:
#include <iostream>
#include <string>
struct A
{
std::string Ip;
std::string port;
std::string sessionkey;
};
int main()
{
std::string m_ip;
std::string m_port;
std::string m_sessionkey;
A a;
a.Ip = "10.43.160.94111";
a.port = "12345";
a.sessionkey = "12Abcd12345Abcd12345Abcd1234512";
// copy data from a to local variables
m_ip = a.Ip;
m_port = a.port;
m_sessionkey = a.sessionkey;
std::cout << "m_ip:" << m_ip << std::endl;
std::cout << "m_port:" << m_port << std::endl;
std::cout << "m_sessionkey:" << m_sessionkey << std::endl;
}
If you insist on using strcpy you must include the C header file string.h either by using #include <string.h> or by using #include <cstring>. Note that this is a C header file and it is distinctly different than the C++ #include <string> header file.
You should change your code like this:
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
struct A
{
char* Ip;
char* port;
char* sessionkey;
};
int main()
{
char m_ip[16];
char m_port[6];
char m_sessionkey[32];
A a;
a.Ip = "10.43.160.94111";
a.port = "12345";
a.sessionkey = "12Abcd12345Abcd12345Abcd1234512";
strcpy(m_ip,a.Ip);
strcpy(m_port,a.port);
strcpy(m_sessionkey,a.sessionkey);
cout << "m_ip:" << m_ip << endl;
cout << "m_port:" << m_port << endl;
cout << "m_sessionkey:" << m_sessionkey << endl;
}
strcpy() function is in cstring header file in C++/C++11, so you must add #include<cstring> to your code.

What is the best way to retreieve an integer from a byte array in C++

Right now I am converting an int to a bytes array this way:
int num = 16777215;
char* bytes = static_cast<char*>(static_cast<void*>(&num));
Is this the best way to do it?
Also, how can I retrieve the int value from that array?
If you want the bytes, you are using the wrong cast:
char* bytes = reinterpret_cast<char*>(&num);
Same for the other way around:
int num = *reinterpret_cast<int*>(bytes);
Note that in general you can't do this, char is special, so you might want to look up aliasing.
In response to
Is there any way to cast it directly to a vector?
You could do something like this:
#include <vector>
#include <cstdint>
template <class T>
std::vector<uint8_t> toByteVector(T value)
{
std::vector<uint8_t> vec = (std::vector<uint8_t>
(reinterpret_cast<uint8_t*>(&value),
(reinterpret_cast<uint8_t*>(&value))+sizeof(T))
);
dumpBytes<T>(vec);
return vec; // RVO to the rescue
}
// just for dumping:
#include <iostream>
#include <typeinfo>
#include <iomanip>
template <class T>
void dumpBytes(const std::vector<uint8_t>& vec)
{
std::cout << typeid(T).name() << ":\n";
for (auto b : vec){
// boost::format is so much better for formatted output.
// Even a printf statement looks better!
std::cout << std::hex << std::setfill('0') << std::setw(2)
<< static_cast<int>(b) << " "
;
}
std::cout << std::endl;
}
int main()
{
uint16_t n16 = 0xABCD;
uint32_t n32 = 0x12345678;
uint64_t n64 = 0x0102030405060708;
toByteVector(n16);
toByteVector(n32);
toByteVector(n64);
return 0;
}

Converting char to int c++

I'm loosing my mind at the moment and below is what I'm trying to do.
char* buffer;
sprintf(buffer, "0x%08x", 5);
*(int *)(0x834AF2AC + 0x1a) = ?buffer?;
Buffer = 0x05000000
I need to set that in memory, if I just set 05 it will set 0x00000005
Question asked better.
How can I convert an INT into a format of "0x%08x"
So 5 becomes 0x05000000
ANSWERD:
The correct answer is *(int *)(0x834AF2AC + 0x1a) = 5<<24;
Something like this:
#include <iostream> // for std::cout, std::endl
#include <string> // for std::string, std::stoi
int main()
{
std::string s{"0x05"};
int i = std::stoi(s, nullptr, 16); // convert base 16 number in s to int
std::cout << i << std::endl;
}
Two result from google which points to stackoverflow (result 1 and 2).
Convert char to int in C and C++
C char* to int conversion
I'm not sure if I understand correctly but if you want to convert an entire string to int, then I would suggest stringstream.
http://www.cplusplus.com/reference/sstream/stringstream/stringstream/
For hexadecimal string:
#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::stringstream
int main () {
std::stringstream ss;
ss << std::hex << 0x05;
int foo;
ss >> foo;
std::cout << "foo: " << foo << '\n';
return 0;
}

Lexical cast Partial conversion - Is it possible?

lexical_cast throws an exception in the following case. Is there a way to use lexical_cast and convert the string to integer.
#include <iostream>
#include "boost/lexical_cast.hpp"
#include <string>
int main()
{
std::string src = "124is";
int iNumber = boost::lexical_cast<int>(src);
std::cout << "After conversion " << iNumber << std::endl;
}
I understand, I can use atoi instead of boost::lexical_cast.
If I'm understanding your requirements correctly it seems as though removing the non-numeric elements from the string first before the lexical_cast will solve your problem. The approach I outline here makes use of the isdigit function which will return true if the given char is a digit from 0 to 9.
#include <iostream>
#include "boost/lexical_cast.hpp"
#include <string>
#include <algorithm>
#include <cctype> //for isdigit
struct is_not_digit{
bool operator()(char a) { return !isdigit(a); }
};
int main()
{
std::string src = "124is";
src.erase(std::remove_if(src.begin(),src.end(),is_not_digit()),src.end());
int iNumber = boost::lexical_cast<int>(src);
std::cout << "After conversion " << iNumber << std::endl;
}
The boost/lexical_cast uses stringstream to convert from string to other types,so you must make sure the string can be converted completely! or, it will throw the bad_lexical_cast exception,This is an example:
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
#define ERROR_LEXICAL_CAST 1
int main()
{
using boost::lexical_cast;
int a = 0;
double b = 0.0;
std::string s = "";
int e = 0;
try
{
// ----- string --> int
a = lexical_cast<int>("123");//good
b = lexical_cast<double>("123.12");//good
// -----double to string good
s = lexical_cast<std::string>("123456.7");
// ----- bad
e = lexical_cast<int>("abc");
}
catch(boost::bad_lexical_cast& e)
{
// bad lexical cast: source type value could not be interpreted as target
std::cout << e.what() << std::endl;
return ERROR_LEXICAL_CAST;
}
std::cout << a << std::endl; // cout:123
std::cout << b << std::endl; //cout:123.12
std::cout << s << std::endl; //cout:123456.7
return 0;
}

How to convert Byte Array to Hexadecimal String in C++?

I am looking for a fastest way to convert a byte array of arbitrary length to a hexadecimal string. This question has been fully answered here at StackOverflow for C#. Some solutions in C++ can be found here.
Are there any "turnkey" or "ready-made" solutions to a problem? C-style solutions are welcome.
#include <vector>
#include <iostream>
#include <algorithm>
#include <string>
#include <iterator>
#include <sstream>
#include <iomanip>
int main()
{
std::vector<unsigned char> v;
v.push_back( 1 );
v.push_back( 2 );
v.push_back( 3 );
v.push_back( 4 );
std::ostringstream ss;
ss << std::hex << std::uppercase << std::setfill( '0' );
std::for_each( v.cbegin(), v.cend(), [&]( int c ) { ss << std::setw( 2 ) << c; } );
std::string result = ss.str();
std::cout << result << std::endl;
return 0;
}
Or, if you've got a compiler that supports uniform initialization syntax and range based for loops you can save a few lines.
#include <vector>
#include <sstream>
#include <string>
#include <iostream>
#include <iomanip>
int main()
{
std::vector<unsigned char> v { 1, 2, 3, 4 };
std::ostringstream ss;
ss << std::hex << std::uppercase << std::setfill( '0' );
for( int c : v ) {
ss << std::setw( 2 ) << c;
}
std::string result = ss.str();
std::cout << result << std::endl;
}
Use boost::alogorithm::hex
std::vector<unsigned char> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
std::string res;
boost::algorithm::hex(v.begin(), v.end(), back_inserter(res));
You can use the C++ Standard Library and or you can use boost::lexical_cast
#include <iostream>
#include <string>
#include <array>
#include <vector>
#include <sstream>
#include <iomanip>
#include <algorithm>
using namespace std;
// use this macro for c++11 feature
#define USE_CPP11
int main(int argc, char* argv[])
{
array<unsigned char, 3> hexArr = {0x01, 0xff, 0x55};
const char separator = ' '; // separator between two numbers
ostringstream os;
os << hex << setfill('0'); // set the stream to hex with 0 fill
#ifdef USE_CPP11
std::for_each(std::begin(hexArr), std::end(hexArr), [&os, &separator] (int i)
{
os << setw(2) << i << separator;
});
#else // c++03
typedef array<unsigned char, 3>::const_iterator const_iterator;
for (const_iterator it = hexArr.begin(); it != hexArr.end(); ++it)
{
os << setw(2) << int(*it) << separator;
}
#endif
os << dec << setfill(' '); // reset the stream to "original"
// print the string
cout << "the string array is: " << os.str() << endl;
return EXIT_SUCCESS;
}
One of the fastest way I know in C++ 11:
template <size_t byteCount>
string BytesArrayToHexString( const std::array<byte, byteCount>& src )
{
static const char table[] = "0123456789ABCDEF";
std::array<char, 2 * byteCount + 1> dst;
const byte* srcPtr = &src[0];
char* dstPtr = &dst[0];
for (auto count = byteCount; count > 0; --count)
{
unsigned char c = *srcPtr++;
*dstPtr++ = table[c >> 4];
*dstPtr++ = table[c & 0x0f];
}
*dstPtr = 0;
return &dst[0];
}
A good compiler should not have any problem to apply SSE optimization on this....