Write formatted mac address to stringstream - c++

I have a the following class (only partial, much more fields in a class)
class Network{
public:
string src_ip_;
string alternative_src_ip_;
array<unsigned char,6> mac_;
string toString(){
stringstream ss;
ss << src_ip_ << SEPERATOR << alternative_src_ip_ << SEPERATOR ;
return ss.str();
}
}
I want to add a formatted mac (with :) to the toString method?
Is there a simple way to adopt my printMac method (by generelize or by write new one) that will do this with combined in the << operator
void printMac(array<unsigned char, 6> mac) {
printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
(unsigned char) mac[0], (unsigned char) mac[1],
(unsigned char) mac[2], (unsigned char) mac[3],
(unsigned char) mac[4], (unsigned char) mac[5]);
}

Use the IO manipulators:
std::ostringstream s;
unsigned char arr[6] = { 0, 14, 10, 11, 89, 10 };
s << std::hex << std::setfill('0');
for (int i = 0; i < sizeof(arr); i++)
{
if (i > 0) s << ':';
// Need to:
// - set width each time as it only
// applies to the next output field.
// - cast to an int as std::hex is for
// integer I/O
s << std::setw(2) << static_cast<int>(arr[i]);
}

You can replace your use of printf with sprintf and then use it to implement operator<< for ostreams
void printMac(array<unsigned char, 6> mac, char (&out)[18]) {
sprintf(out, "%02x:%02x:%02x:%02x:%02x:%02x",
(unsigned char) mac[0], (unsigned char) mac[1],
(unsigned char) mac[2], (unsigned char) mac[3],
(unsigned char) mac[4], (unsigned char) mac[5]);
}
std::ostream &operator<<(std::ostream &os, std::array<unsigned char, 6> mac) {
char buf[18];
printMac(mac, buf);
return os << buf << '\n';
}

If you want to maintain printf-like code, you could try Boost.Format.
ss << boost::format("%02x:%02x:%02x:%02x:%02x:%02x\n") % mac[0] % mac[1] % mac[2] % mac[3] % mac[4] % mac[5];

Related

Converting unsigned char * to hexstring

Below code takes a hex string(every byte is represented as its corresponidng hex value)
converts it to unsigned char * buffer and then converts back to hex string.
This code is testing the conversion from unsigned char* buffer to hex string
which I need to send over the network to a receiver process.
I chose hex string as unsigned char can be in range of 0 to 255 and there is no printable character after 127.
The below code just tells the portion that bugs me. Its in the comment.
#include <iostream>
#include <sstream>
#include <iomanip>
using namespace std;
// converts a hexstring to corresponding integer. i.e "c0" - > 192
int convertHexStringToInt(const string & hexString)
{
stringstream geek;
int x=0;
geek << std::hex << hexString;
geek >> x;
return x;
}
// converts a complete hexstring to unsigned char * buffer
void convertHexStringToUnsignedCharBuffer(string hexString, unsigned char*
hexBuffer)
{
int i=0;
while(hexString.length())
{
string hexStringPart = hexString.substr(0,2);
hexString = hexString.substr(2);
int hexStringOneByte = convertHexStringToInt (hexStringPart);
hexBuffer[i] = static_cast<unsigned char>((hexStringOneByte & 0xFF)) ;
i++;
}
}
int main()
{
//below hex string is a hex representation of a unsigned char * buffer.
//this is generated by an excryption algorithm in unsigned char* format
//I am converting it to hex string to make it printable for verification pupose.
//and takes the hexstring as inpuit here to test the conversion logic.
string inputHexString = "552027e33844dd7b71676b963c0b8e20";
string outputHexString;
stringstream geek;
unsigned char * hexBuffer = new unsigned char[inputHexString.length()/2];
convertHexStringToUnsignedCharBuffer(inputHexString, hexBuffer);
for (int i=0;i<inputHexString.length()/2;i++)
{
geek <<std::hex << std::setw(2) << std::setfill('0')<<(0xFF&hexBuffer[i]); // this works
//geek <<std::hex << std::setw(2) << std::setfill('0')<<(hexBuffer[i]); -- > this does not work
// I am not able to figure out why I need to do the bit wise and operation with unsigned char "0xFF&hexBuffer[i]"
// without this the conversion does not work for individual bytes having ascii values more than 127.
}
geek >> outputHexString;
cout << "input hex string: " << inputHexString<<endl;
cout << "output hex string: " << outputHexString<<endl;
if(0 == inputHexString.compare(outputHexString))
cout<<"hex encoding successful"<<endl;
else
cout<<"hex encoding failed"<<endl;
if(NULL != hexBuffer)
delete[] hexBuffer;
return 0;
}
// output
// can some one explain ? I am sure its something silly that I am missing.
the C++20 way:
unsigned char* data = new unsigned char[]{ "Hello world\n\t\r\0" };
std::size_t data_size = sizeof("Hello world\n\t\r\0") - 1;
auto sp = std::span(data, data_size );
std::transform( sp.begin(), sp.end(),
std::ostream_iterator<std::string>(std::cout),
[](unsigned char c) -> std::string {
return std::format("{:02X}", int(c));
});
or if you want to store result into string:
std::string result{};
result.reserve(size * 2 + 1);
std::transform( sp.begin(), sp.end(),
std::back_inserter(result),
[](unsigned char c) -> std::string {
return std::format("{:02X}", int(c));
});
Output:
48656C6C6F20776F726C640A090D00
The output of an unsigned char is like the output of a char which obviously does not what the OP expects.
I tested the following on coliru:
#include <iomanip>
#include <iostream>
int main()
{
std::cout << "Output of (unsigned char)0xc0: "
<< std::hex << std::setw(2) << std::setfill('0') << (unsigned char)0xc0 << '\n';
return 0;
}
and got:
Output of (unsigned char)0xc0: 0�
This is caused by the std::ostream::operator<<() which is chosen out of the available operators. I looked on cppreference
operator<<(std::basic_ostream) and
std::basic_ostream::operator<<
and found
template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,
unsigned char ch );
in the former (with a little bit help from M.M).
The OP suggested a fix: bit-wise And with 0xff which seemed to work. Checking this in coliru.com:
#include <iomanip>
#include <iostream>
int main()
{
std::cout << "Output of (unsigned char)0xc0: "
<< std::hex << std::setw(2) << std::setfill('0') << (0xff & (unsigned char)0xc0) << '\n';
return 0;
}
Output:
Output of (unsigned char)0xc0: c0
Really, this seems to work. Why?
0xff is an int constant (stricly speaking: an integer literal) and has type int. Hence, the bit-wise And promotes (unsigned char)0xc0 to int as well, yields the result of type int, and hence, the std::ostream::operator<< for int is applied.
This is an option to solve this. I can provide another one – just converting the unsigned char to unsigned.
Where the promotion of unsigned char to int introduces a possible sign-bit extension (which is undesired in this case), this doesn't happen when unsigned char is converted to unsigned. The output stream operator for unsigned provides the intended output as well:
#include <iomanip>
#include <iostream>
int main()
{
std::cout << "Output of (unsigned char)0xc0: "
<< std::hex << std::setw(2) << std::setfill('0') << (unsigned)(unsigned char)0xc0 << '\n';
const unsigned char c = 0xc0;
std::cout << "Output of unsigned char c = 0xc0: "
<< std::hex << std::setw(2) << std::setfill('0') << (unsigned)c << '\n';
return 0;
}
Output:
Output of (unsigned char)0xc0: c0
Output of unsigned char c = 0xc0: c0
Live Demo on coliru

std::hex does not work as I expect

I'm not used to C++, so bear with me...
Two bytes are read from a device and gets in a buffer.
It is then to be printed.
The code below is supposed to return the string "0x204D"
However, it returns "0x M" which in hex is 30 78 20 4d
So the hex is not decoded to ascii.
void vito_unit::decodeAsRaw(unsigned char *buffer, int bufferLen)
{
std::stringstream *decodedClearText;
decodedClearText = new std::stringstream;
*decodedClearText << "0x" << std::hex;
for (int i=0; i<bufferLen; i++) {
*decodedClearText << buffer[i];
}
setValue(decodedClearText->str());
}
How should it be done?
This has nothing to do with std::hex.
When you stream a [signed/unsigned] char, its ASCII representation is used, because that is usually what is expected of chars.
You can stream a number instead by converting it to int. Then the feature that renders numbers in hexadecimal notation (i.e. std::hex) will be triggered.
You should also fix that memory leak and unnecessary dynamic allocation:
void vito_unit::decodeAsRaw(unsigned char const* const buffer, int const bufferLen)
{
std::stringstream decodedClearText;
decodedClearText << "0x" << std::hex;
for (int i = 0; i < bufferLen; i++) {
decodedClearText << +buffer[i];
}
setValue(decodedClearText.str());
}
The unary "+" performs an integral promotion to int.
buffer[i] is of type unsigned char and is thus printed as a character instead of its hexadecimal representation. You can cast the value to an unsigned int to avoid that.
void vito_unit::decodeAsRaw(unsigned char *buffer, int bufferLen)
{
std::stringstream *decodedClearText;
decodedClearText = new std::stringstream;
*decodedClearText << "0x" << std::hex;
for (int i=0; i<bufferLen; i++) {
*decodedClearText << (unsigned int) buffer[i];
}
setValue(decodedClearText->str());
}
The hint from Bo Persson was what I needed.
for (int i=0; i<bufferLen; i++) {
*decodedClearText << (int)buffer[i];
}
did the trick.

How can to convert hexadecimal to string? C++

I have an array of hexadecimals and I need to convert it to string.
my array:
// declaration
unsigned char HEX_bufferMessage[12];
// initialize
HEX_bufferMessage[0] = 0xF0;
HEX_bufferMessage[1] = 0x15;
HEX_bufferMessage[2] = 0x31;
HEX_bufferMessage[3] = 0x02;
HEX_bufferMessage[4] = 0x03;
HEX_bufferMessage[5] = 0x00;
HEX_bufferMessage[6] = 0x00;
HEX_bufferMessage[7] = 0xD1;
HEX_bufferMessage[8] = 0xD1;
HEX_bufferMessage[9] = 0x00;
HEX_bufferMessage[10] = 0x00;
HEX_bufferMessage[11] = 0xF7;
I only have these informations in hexadecimal format, I need to convert them to string. Anyone know how I can do it??
Thank you!!
Late to the party, but since all the answers using std::to_string() fail to output the hex values as hex values, I suggest you send them to a stream, where you can format your output via std::hex:
std::cout << "0x" << std::hex << HEX_bufferMessage[0] << std::endl;
or, if you want to use it in a string:
std::string to_hex_string( const unsigned int i ) {
std::stringstream s;
s << "0x" << std::hex << i;
return s.str();
}
or even in a single line:
// ...
return (static_cast<std::stringstream const&>(std::stringstream() << "0x" << std::hex << i)).str();
std::bitset<16> foo(HEX_bufferMessage[0]);
std::string s = foo.to_string();
http://en.cppreference.com/w/cpp/utility/bitset/to_string
Use : std::to_string
for (size_t i =0 ; i<10; ++i)
{
std::string s { std::to_string(HEX_bufferMessage[i]) }; //ith element
std::cout << s; //concatenate all s as per need
}
something like this?
const char *hex = "0123456789ABCDEF";
unsigned char x = 0xF8;
std::cout << "0x" << hex[x >> 4 & 0xF] << hex[x & 0xF] << std::endl;
How about std::to_string?
Like
std::string s;
for (auto const& v : HEX_bufferMessage)
s += std::to_string(v);
char hex_string[12*2+1]; /* where 12 - is the number of you hex values, 2 - is 2 chars per each hex, and 1 is the final zero character */
for(int i=0;i<12;++i) {
sprintf(hex_string+i*2,"%x", HEX_bufferMessage[i]);
}

int to Hex string (C++)

I have done some research on how to convert an int to Hex string and found an answer, however what i need is a little bit different as you can see in the following code:
int addr = 5386; //
std::string buffer = "contains 0xCCCCCCCC as hex (non ASCII in the string)";
size_t idx = 0;
idx = buffer.find("\xCC\xCC\xCC\xCC", idx);
if (idx != string::npos) buffer.replace(idx, 4, XXX); // here i want to put the addr variable but as 0x0000150A
What i need is a way to convert the addr variable to a hex string that has the \x in between the bytes like "\x0a\x15\x00\x00"
Thanks in advance.
Maybe this program would help you :
#include <sstream>
#include <iomanip>
#include <iostream>
int main(int argc, char const *argv[])
{
int a = 5386;
std::ostringstream vStream;
for(std::size_t i = 0 ; i < 4 ; ++i)
vStream << "\\x"
<< std::right << std::setfill('0') << std::setw(2) << std::hex
<< ((a >> i*4) & 0xFF);
std::cout << vStream.str() << std::endl;
return 0;
}
I am not sure I precisely got your problem, but I understand you want an int to be transformed into a string in format : "\xAA\xAA\xAA\xAA".
It uses std::right, std::setfill('0') and std::setw(2) to force an output of "2" to be "02". std::hex is to get the hexadecimal representation of a integer.
You may want to treat addr as char*, but you will have issues with endianness.
you may do the job manually with something like:
unsigned int addr = 5386 // 0x0000150A
char addrAsHex[5] = {(addr >> 24) & 0xFF, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF, 0};
// ...
buffer.replace(idx, 4, addrAsHex);
Something like this:
char buf[20];
uint32_t val;
sprintf(buf, "\\x%02x\\x%02x\\x%02x\\x%02x",
(val >> 24), (uint8_t)(val >> 16), (uint8_t)(val >> 8), (uint8_t)val);

What is the proper way to create a temporary char* and print to it?

I have a helper function that takes an unsigned char array of a fixed length, and returns it as a formatted char *. However, I'm having some problems.
I tried
char* byteArrayToString(unsigned char byte[6]) {
char t[18] = {""};
char* str = t;
sprintf(str, "%02X:%02X:%02X:%02X:%02X:%02X", byte[0], byte[1], byte[2], byte[3], byte[4], byte[5]);
return str;
}
and
char* byteArrayToString(unsigned char byte[6]) {
std::string t = "";
char* str = t;
sprintf(str, "%02X:%02X:%02X:%02X:%02X:%02X", byte[0], byte[1], byte[2], byte[3], byte[4], byte[5]);
return str;
}
and
char* byteArrayToString(unsigned char byte[6]) {
char* str = new char();
sprintf(str, "%02X:%02X:%02X:%02X:%02X:%02X", byte[0], byte[1], byte[2], byte[3], byte[4], byte[5]);
return str;
}
The second one results in some side effects of the value of that string being changed. The first one ends up giving me junk values and the last seg faults (but I can't figure out why).
The problem with your first one is not in the printing, but in the returning. You're returning a pointer to an array which has been reclaimed (because it is an automatic variable, its lifetime ends when the function returns).
Instead try:
string byteArrayToString(const unsigned char* const byte)
{
char t[18] = {""};
sprintf(t, "%02X:%02X:%02X:%02X:%02X:%02X", byte[0], byte[1], byte[2], byte[3], byte[4], byte[5]);
return t;
}
Proper way is to return std::string as:
#include <sstream> //for std::ostringstream
#include <string> //for std::string
#include <iomanip> //for std::setw, std::setfill
std::string byteArrayToString(unsigned char byte[6])
{
std::ostringstream ss;
for(size_t i = 0 ; i < 5 ; ++i)
ss << "0X" << std::hex << std::setw(2) << std::setfill('0') << (int) byte[i] << ":";
ss << "0X" << std::hex << std::setw(2) << std::setfill('0') << (int) byte[5];
return ss.str();
}
Online demo
On the callsite you can get const char* as:
std::string s = byteArrayToString(bytes);
const char *str = s.c_str();