stringstream >> uint8_t in hex? c++ - c++

i am confused by the output of the following code:
uint8_t x = 0, y = 0x4a;
std::stringstream ss;
std::string a = "4a";
ss << std::hex << a;
ss >> x;
std::cout << (int)x << " "<< (int)y << std::endl;
std::cout << x << " "<< y <<std::endl;
std::cout << std::hex << (int)x << " " << (int)y << std::endl;
uint8_t z(x);
std::cout << z;
the output for the above is:
52 74
4 J
34 4a
4
and when we change replace the first line with:
uint16_t x = 0, y = 0x4a;
the output turns into:
74 74
74 74
4a 4a
J
I think i understand what happens but i don't understand why it happens or how i can prevent it/work around it. From my understanding std::hex modifier is somehow undermined because of the type of x, maybe not exactly true at a technical level but it simply just writes the first character it reads.
Background: The input is supposed to be a string of hexadecimal digits, each pair representing a byte( just like a bitmap except in string). I want to be able to read each byte and store it in a uint8_t so i was experimenting with that when i came across this problem. I still can't determine what's the best method of this so if you think what i'm doing is inefficient or unnecessary i would appreciate to know why. Thank you for reading,

ss >> x
is treating uint8_t x as an unsigned char. The ascii value of '4' is (decimal) 52. It's reading the first char of the string "4a" into x as if x were a character. When you switch it to uint16_t, it's treating it as an unsigned short integer type. Same with y.

Related

Converting HEXA 64 bits numbers to int

I'm making a college job, a conversion between hexa numbers enclosed in a stringstream. I have a big hexa number (a private key), and I need to convert to int, to put in a map<int,int>.
So when I run the code, the result of conversion is the same for all the two hexa values inserted, what is incorrect, it should be differente results after conversion. I think it's an int sizes stack problem, because when I insert short hexas, it works greatly. As shown below the hexa has 64 bits.
Any idea to get it working?
int main()
{
unsigned int x;
std::stringstream ss;
ss << std::hex << "0x3B29786B4F7E78255E9F965456A6D989A4EC37BC4477A934C52F39ECFD574444";
ss >> x;
std::cout << "Saida" << x << std::endl;
// output it as a signed type
std::cout << "Result 1: " << static_cast<std::int64_t>(x) << std::endl;
ss << std::hex << "0x3C29786A4F7E78255E9A965456A6D989A4EC37BC4477A934C52F39ECFD573344";
ss >> x;
std::cout << "Saida 2 " << x << std::endl;
// output it as a signed type
std::cout << "Result 2: " << static_cast<std::int64_t>(x) << std::endl;
}
Firstly, the HEX numbers in your examples do not fit into an unsigned int.
You should clear the stream before loading the second HEX number there.
...
std::cout << "Result 1: " << static_cast<std::int64_t>(x) << std::endl;
ss.clear();
ss << std::hex << "0x3C29786A4F7E78255E9A965456A6D989A4EC37BC4477A934C52F39ECFD573344";
ss >> x;
...
Each hexadecimal digit equates to 4 bits (0xf -> 1111b). Those hex strings are both 64 x 4 = 256 bits long. You're looking at a range error.
You need to process the input 16 characters at a time. Each character is 4 bits. The 16 first characters will give you an unsigned 64-bit value. (16x4 is 64)
Then you can put the fist value in a vector or other container and move on to the next 16 characters. If you have questions about string manipulation, search this site for similar questions.

How to convert int to binary and concatenate as char in C++

I have two values, 0 and 30, I need to store it's binary representation on one byte for each. Like:
byte 0 = 00000000
byte 1 = 00011110
and then concatenate them on a string that will print the ASCII for 0 (NULL) and for 30 (Record Separator). So, not print "030", but something I can't really right here and neither the command can print properly. I know those are not nice things to print.
I was doing like this:
string final_message = static_cast<unsigned char>(bitset<8>(0).to_ulong());
final_message += static_cast<unsigned char>((bitset<8>(answer.size())).to_ulong()); // where answer.size() = 30
cout << final_message << endl;
Not sure if it's right, I never worked with bitset since now. I think it's right but the server that receives my messages keep telling me that the numbers are wrong. I'm pretty sure that the numbers I need are 0 and 30 on that order, so, as the only part I'm not sure how it works are those three lines, I'm putting this question here.
Those three lines are right? There's a better way to do that?
A byte (or a char) holds a single 8-bit value, and the value is the same whether you "view" it in a binary format, in a decimal format, or as a character to be printed on the console. It's just the way you look at it.
See the following example. The first two examples byte1 and byte2 are those referred in your question. Unfortunately, you won't see much on the console.
Therefore I added another example, which illustrates three ways of viewing the same value 65 in different ways. Hope it helps.
int main(){
char byte1 = 0b00000000;
char byte2 = 0b00011110;
std::cout << "byte1 as 'int value': " << (int)byte1 << "; and as character: " << byte1 << endl;
std::cout << "byte2 as 'int value': " << (int)byte2 << "; and as character: " << byte2 << endl;
char a1 = 65;
char a2 = 'A';
char a3 = 0b001000001;
std::cout << "a1 as 'int value': " << (int)a1 << "; and as character: " << a1 << endl;
std::cout << "a2 as 'int value': " << (int)a2 << "; and as character: " << a2 << endl;
std::cout << "a3 as 'int value': " << (int)a3 << "; and as character: " << a3 << endl;
return 0;
}
Output:
byte1 as 'int value': 0; and as character:
byte2 as 'int value': 30; and as character:
a1 as 'int value': 65; and as character: A
a2 as 'int value': 65; and as character: A
a3 as 'int value': 65; and as character: A
The line
string final_message = static_cast<unsigned char>(bitset<8>(0).to_ulong());
does not compile. And obviously, there is no need for bitset here as you are essentially juts add extra conversions in the path.
If I split the line above in 2 and use +=, the resulting string as a size of 2 and contain characters with values of 0 and 30 (I have inspected in using the debugger).
So I don't know what is your problem as it appears to do what you want...

Printing out the hex vale of an unsigned char array in C++

I want to print out the hex value of an unsigned char array using the cout function.
The most obvious approach would be something like the following.
unsigned char str[] = "foo bar baz\n";
for(unsigned short int i = 0; i < sizeof(str); i++){
std::cout << std::hex << str[i] << std::dec << ' ';
}
std::cout << std::endl;
Suprisingly, this outputs the following string:
foo bar baz
For some reason this does not print out the proper hexadecimal value of str
How can I cout the proper hex value of str?
To cout the proper hex value of an unsigned char, it will need to be converted to an integer first.
unsigned char str[] = "foo bar baz\n";
for(unsigned short int i = 0; i < sizeof(str); i++){
std::cout << std::hex << (int) str[i] << std::dec << ' ';
}
std::cout << std::endl;
Gives the following output.
66 6f 6f 20 62 61 72 20 62 61 7a 00
Which corresponds with the hex value of each unsigned char in str.
An explaination for this can be found in the following std::hex documentation.
std::hex
Sets the basefield format flag for the str stream to hex.
When basefield is set to hex, integer values inserted into the stream are expressed in hexadecimal base (i.e., radix 16). For input streams, extracted values are also expected to be expressed in hexadecimal base when this flag is set.
http://www.cplusplus.com/reference/ios/hex/

Function behave differently with similar input (C++)

I am trying to work with the modbus protocol and right now i am calculating the LRC of the messages. I made a function which worked with no issue whatever i was putting into and then i noticed that id did not worked with one input and i can't find a logical explanation on why this don't work.
The function is :
void LRCstring(std::string example)
{
std::stringstream ss;
std::string hex =example.substr(1, example.length()-5);
std::vector<unsigned char> hexCh;
unsigned int buffer;
int offset = 0;
while (offset < hex.length()) {
ss.clear();
ss << std::hex << hex.substr(offset, 2);
ss >> buffer;
hexCh.push_back(static_cast<unsigned char>(buffer));
offset += 2;
}
unsigned char LRC=0x00;
int i;
for (i=0;i<hexCh.size();i++)
{
LRC=LRC+hexCh[i];
}
LRC = 0xFF-LRC; // 1 complement
LRC = LRC+1; // 2 complement
//std::string s = std::to_string(LRC);
//int deci = atoi(s.c_str());
int deci = LRC;
int reste=deci % 16;
std::string temp;
int partiehexa=(deci-reste)/16;
std::string temp2;
std::cout << "deci : " << deci << std::endl;
std::cout << "reste : " << reste << std::endl;
std::cout << "partiehexa : " << partiehexa << std::endl;
std::stringstream ss2;
ss2 << reste;
ss2 >> temp;
ss2 << partiehexa;
ss2 >> temp2;
if (partiehexa<10) {LRCascii+=temp2;}
if (partiehexa==10) {LRCascii+='A';}
if (partiehexa==11) {LRCascii+='B';}
if (partiehexa==12) {LRCascii+='C';}
if (partiehexa==13) {LRCascii+='D';}
if (partiehexa==14) {LRCascii+='E';}
if (partiehexa==15) {LRCascii+='F';}
if (reste<10) {LRCascii+=temp;}
if (reste==10) {LRCascii+='A';}
if (reste==11) {LRCascii+='B';}
if (reste==12) {LRCascii+='C';}
if (reste==13) {LRCascii+='D';}
if (reste==14) {LRCascii+='E';}
if (reste==15) {LRCascii+='F';}
std::cout << "LRC : " << LRCascii << std::endl;
return;
}
Examples on what is the input and the result when it is working :
input > ":040100130013??\r\n"
The cout display "LRC : D5"
input > ":0401CD6B05??\r\n"
The cout display "LRC : BE"
D5 and BE are the right results.
I tried with other inputs and had no problem until this :
input > ":0403006B0003??\r\n"
The cout display "LRC : B"
input > ":040306022B00000064??\r\n"
The cout display "LRC : 2"
It should be 8B and not simply B and it should be 62 and not simply 2.
We can see that the last part of the LRC is good but the other part is ignored. What is even stranger is that in this case the cout of "partiehexa" is showing "8" and "6", it is not like this int was empty. I fail to understand why this is happening in this case.
To me it seems to a C code. But I did quickly analyze your code. I Think the problem lies where your are calculating the
(partiehexa < 10)
The LRCascii only gets assigned while looping through the "reste" part of the code. In the "partiehexa" part of the code it do not get assigned to anything.
Suggestion: Change the code to the following and your code will work
if (partiehexa<10)
{
std::stringstream ss3;
ss3 << partiehexa;
ss3 >> temp2;
LRCascii += temp2;
}
Best solution would be to rewrite the code in proper optimized way.
To calculate the LRC
Add up all the data bytes in the message (before converting to ASCII and without the initial colon and final CR/LF).
Throw away any bits that carry over 8 bits.
Make the result negative (by twos compliment) to get the LRC byte.
In your example, checksum can be calculated mathematically as below:
String: 040306022B00000064
Checksum: 62
Byte# 1 Hex Value 04 Decimal Value 4
Byte# 2 Hex Value 03 Decimal Value 3
Byte# 3 Hex Value 06 Decimal Value 6
Byte# 4 Hex Value 02 Decimal Value 2
Byte# 5 Hex Value 2B Decimal Value 43
Byte# 6 Hex Value 00 Decimal Value 0
Byte# 7 Hex Value 00 Decimal Value 0
Byte# 8 Hex Value 00 Decimal Value 0
Byte# 9 Hex Value 64 Decimal Value 100
Total Hex Value 9E Decimal Value 158
LRC: Hex Value FFFFFFFF62 Decimal Value -158
So the single Hex LRC Byte in this example is 62.
Prashant..

C++ sign extension

I am working on a homework problem, printing from a binary file.
I have searched and found out that my problem is a sign extension problem.
In c the correct action would be to cast to an (unsigned char)
I have tried this solution and it does not work with cout
output with (unsigned) is:
4D 5A FFFFFF90 00 03 00 00 00 04 00 00 00 FFFFFFFF FFFFFFFF 00 00
output with (unsigned char) is:
0M 0Z 0ê 0� 0 0� 0� 0� 0 0� 0� 0� 0ˇ 0ˇ 0� 0�
Any guidance would be most helpful;
Here is the code:
void ListHex(ifstream &inFile)
{
// declare variables
char buf[NUMCHAR];
unsigned char bchar;
while(!inFile.eof())
{
inFile.read(buf,NUMCHAR);
for (int count = 0; count < inFile.gcount(); ++count)
{
cout << setfill('0') << setw(2) << uppercase << hex <<
(unsigned)buf[count] << ' ';
}
cout << '\n';
}
}
How about cout <<setfill('0') << setw(2) << uppercase << hex << (0xFF & buf[count])
void ListHex(std::istream& inFile) {
// declare variables
char c;
while(inFile >> c) {
std::cout << std::setw(2) << std::hex
<< static_cast<int>(c);
}
}
I would recommend do this character by character, the reason being there are all sorts of endian issues I would rather not even think about when dealing with rinterpretive int conversions. The std::ifstream will buffer the chars for you anyway (as will your OS likely too as well).
Notice how we take in the file stream as the more generic std::istream this allows us to pass in any type of istream including std::istringstream, std::cin and std::ifstream.
for example:
ListHex(std::cin);
std::istringstream iss("hello world!");
ListHex(iss);
would hex you user input.
edit
Using a buffer
void ListHex(std::istream& inFile) {
// declare variables
char arr[NUMCHAR];
while(inFile.read(arr, NUMCHAR)) {
for(std::size_t i=0; i!=NUMCHAR; ++i) {
std::cout << std::setw(2) << std::hex
<< static_cast<int>(arr[i]);
}
}
}
You can get rid of the sign extension by masking off the high bits:
(((unsigned) buf[count)) & 0xff)
std::cout prints unsigned char as a character, not an integer. You can perform two casts here – something along the lines of:
static_cast <int> (static_cast <unsigned char> (buf[count]))
Alternatively, use an unsigned char buffer and a single cast:
void ListHext(ifstream& inFile)
{
unsigned char buf[NUMCHAR];
while (inFile.read(reinterpret_cast <char*> (&buf[0]), NUMCHAR))
{
for (int i=0; i < NUMCHAR; ++i)
cout << ... << static_cast <int> (buf[i]) << ' ';
cout << endl;
}
}
Edit:
A mask should not be used here as it assumes a particular character size. The following are equivalent only when CHAR_BIT is 8:
// bad examples
x & 0xFF // note - implicit int conversion
static_cast <int> (x) & 0xFF // note - explicit int conversion
// good example
static_cast <int> (static_cast <unsigned char> (x))