Different behaviors in strringstream given std::hex, uint8_t vs int - c++

I suppose the fact that uint8_t is really just an alias for char means that when the characters in the stringstream get read back in, they are stored natively, i.e. the ascii code for the character, whereas if the char is input to an int, with std::hex specified, it gets read in as a hex digit converted to base 10.
This is a small example exhibiting the behavior, but the reason I'm asking is because I started out under the assumption that specifying an output vector of unit8_t was the right approach, as I need to later feed this vector as an array to a C function as a byte vector (you pass it in as a void pointer and it figures out what do to with it somehow). So I figured reading in pairs of input chars into a string stream and then out into a uint8_t would help me skip manually bitshifting. Is there a way of keeping the idea of reading into a uint8_t but evoking the handling of an int? Can I cast to int at the point of the read from the stringstream? Or what?
#include <iostream>
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <vector>
#include <cstdint>
int main (int argc, char** argv) {
uint8_t n = 0;
std::stringstream ss;
ss << 'F';
ss >> std::hex >> n;
std::cout << "uint8:" << (int)n << std::endl;
int m = 0;
std::stringstream tt;
tt << 'F';
tt >> std::hex >> m;
std::cout << "int:" << std::hex << m << std::endl;
return 0;
}
output
uint8:70
int:f

There are operator>> overloads for char, signed char and unsigned char, which all read a single character from the stream. A uint8_t argument selects the unsigned char overload as the best match, reading F as a character (ASCII code 70 or 0x46).
To match an integer extraction operator>> overload, use an argument of type short or bigger (for example, uint16_t):
uint16_t n = 0;
std::stringstream ss;
ss << 'F';
ss >> std::hex >> n;
Can I cast to int at the point of the read from the stringstream?
No. The argument is taken by reference, which in function calls works as a pointer. Type punning a uint8_t argument as (int&) will invoke undefined behavior. Just use a bigger type instead.

Related

Parsing and turning a string into a number

I have an input file which I'm reading in with the basic myFile >> variable since I know the format and the format will always be correct. The file I'm reading in is formatted as instruction <num> <num> and to make >> work, I'm reading everything in as a string. If I have 3 variables, one to take in each piece of the line, how can I then turn string <1> (for example) into int 1? I know the string's first and last characters are brackets which need to be removed, then I could cast to an int, but I'm new to C++ and would like some insight on the best method of doing this (finding and removing the <>, then casting to int)
use stringstream
#include <string>
#include <sstream>
#include <iostream>
int main() {
std::string str = "<1>";
int value;
std::stringstream ss(str);
char c;
ss >> c >> value >> c;
std::cout << value;
}
First to get the middle character out you can just do char myChar = inputString.at(1);. Then you can do int myInt = (int)myChar;
Even if you remove the <> characters, your still importing the file content into a string using >> so you still need to cast it to an int. If you have only 1 value, you can follow what Nicholas Callahan wrote in the previous answer, but if you have multiple characters you want to read as int, you dont have a choice but to cast.
You can also resort to sscanf.
#include <cstdio>
#include <iostream>
#include <string>
int main()
{
std::string str = "<1234>";
int value;
sscanf(str.c_str(), "<%d>", &value);
std::cout << value << std::endl;
}

string (from substr) conversion to unsigned int

I have a string which actually contains a number and a string, separated by ,, for instance "12,fooBar".
I would like to put it into separated variables, i.e. the number into unsigned int myNum and the string into std::string myStr.
I have the following snipped of code:
size_t pos1=value.find(',');
std::cout << value.substr(0, pos1) << " and "
<< (value.substr(0, pos1)).c_str() << std::endl;
This yields 12 and 1. Anything I missed here? What happend to the 2 in the second part?
Note: I isolated the problem to this snipped of code. I need c_str() to pass it to atoi to get the unsigend int. Here I don't want to print the second part.
Update: I actually get the string from levelDB Get. If I put a test string like I put here, it works.
The posted code produces the same substring: value.substr(0, pos1). Note that std::string::substr() does not modify the object, but returns a new std::string.
Example:
#include <iostream>
#include <string>
int main ()
{
std::string value ="12,fooBar";
unsigned int myNum;
std::string myStr;
const size_t pos1 = value.find(',');
if (std::string::npos != pos1)
{
myNum = atoi(value.substr(0, pos1).c_str());
myStr = value.substr(pos1 + 1);
}
std::cout << myNum << " and "
<< myStr << std::endl;
return 0;
}
Output:
12 and fooBar
EDIT:
If the unsigned int is the only piece required then the following will work:
unsigned int myNum = atoi(value.c_str());
as atoi() will stop at the first non-digit character (excluding optional leading - or +), in this case the ,.
The cleanest C++ style solution to this problem is to use a stringstream.
#include <sstream>
// ...
std::string value = "12,fooBar";
unsigned int myNum;
std::string myStr;
std::stringstream myStream(value);
myStream >> myNum;
myStream.ignore();
myStream >> myStr;
Your second substr should be value.substr(pos1+1,value.length())
One more option is using std::from_chars function from the 17th standard (< charconv > header):
int x;
from_chars(&s[i], &s.back(), x); // starting from character at index i parse
// the nearest interger till the second char pointer
There are different overloads for different types of value x (double etc.).

C++ string to double conversion

Usually when I write anything in C++ and I need to convert a char into an int I simply make a new int equal to the char.
I used the code(snippet)
string word;
openfile >> word;
double lol=word;
I receive the error that
Code1.cpp cannot convert `std::string' to `double' in initialization
What does the error mean exactly? The first word is the number 50. Thanks :)
You can convert char to int and viceversa easily because for the machine an int and a char are the same, 8 bits, the only difference comes when they have to be shown in screen, if the number is 65 and is saved as a char, then it will show 'A', if it's saved as a int it will show 65.
With other types things change, because they are stored differently in memory. There's standard function in C that allows you to convert from string to double easily, it's atof. (You need to include stdlib.h)
#include <stdlib.h>
int main()
{
string word;
openfile >> word;
double lol = atof(word.c_str()); /*c_str is needed to convert string to const char*
previously (the function requires it)*/
return 0;
}
#include <iostream>
#include <string>
using namespace std;
int main()
{
cout << stod(" 99.999 ") << endl;
}
Output: 99.999 (which is double, whitespace was automatically stripped)
Since C++11 converting string to floating-point values (like double) is available with functions:
stof - convert str to a float
stod - convert str to a double
stold - convert str to a long double
As conversion of string to int was also mentioned in the question, there are the following functions in C++11:
stoi - convert str to an int
stol - convert str to a long
stoul - convert str to an unsigned long
stoll - convert str to a long long
stoull - convert str to an unsigned long long
The problem is that C++ is a statically-typed language, meaning that if something is declared as a string, it's a string, and if something is declared as a double, it's a double. Unlike other languages like JavaScript or PHP, there is no way to automatically convert from a string to a numeric value because the conversion might not be well-defined. For example, if you try converting the string "Hi there!" to a double, there's no meaningful conversion. Sure, you could just set the double to 0.0 or NaN, but this would almost certainly be masking the fact that there's a problem in the code.
To fix this, don't buffer the file contents into a string. Instead, just read directly into the double:
double lol;
openfile >> lol;
This reads the value directly as a real number, and if an error occurs will cause the stream's .fail() method to return true. For example:
double lol;
openfile >> lol;
if (openfile.fail()) {
cout << "Couldn't read a double from the file." << endl;
}
If you are reading from a file then you should hear the advice given and just put it into a double.
On the other hand, if you do have, say, a string you could use boost's lexical_cast.
Here is a (very simple) example:
int Foo(std::string anInt)
{
return lexical_cast<int>(anInt);
}
The C++ way of solving conversions (not the classical C) is illustrated with the program below. Note that the intent is to be able to use the same formatting facilities offered by iostream like precision, fill character, padding, hex, and the manipulators, etcetera.
Compile and run this program, then study it. It is simple
#include "iostream"
#include "iomanip"
#include "sstream"
using namespace std;
int main()
{
// Converting the content of a char array or a string to a double variable
double d;
string S;
S = "4.5";
istringstream(S) >> d;
cout << "\nThe value of the double variable d is " << d << endl;
istringstream("9.87654") >> d;
cout << "\nNow the value of the double variable d is " << d << endl;
// Converting a double to string with formatting restrictions
double D=3.771234567;
ostringstream Q;
Q.fill('#');
Q << "<<<" << setprecision(6) << setw(20) << D << ">>>";
S = Q.str(); // formatted converted double is now in string
cout << "\nThe value of the string variable S is " << S << endl;
return 0;
}
Prof. Martinez
Coversion from string to double can be achieved by
using the 'strtod()' function from the library 'stdlib.h'
#include <iostream>
#include <stdlib.h>
int main ()
{
std::string data="20.9";
double value = strtod(data.c_str(), NULL);
std::cout<<value<<'\n';
return 0;
}
#include <string>
#include <cmath>
double _string_to_double(std::string s,unsigned short radix){
double n = 0;
for (unsigned short x = s.size(), y = 0;x>0;)
if(!(s[--x] ^ '.')) // if is equal
n/=pow(10,s.size()-1-x), y+= s.size()-x;
else
n+=( (s[x]-48) * pow(10,s.size()-1-x - y) );
return n;
}
or
//In case you want to convert from different bases.
#include <string>
#include <iostream>
#include <cmath>
double _string_to_double(std::string s,unsigned short radix){
double n = 0;
for (unsigned short x = s.size(), y = 0;x>0;)
if(!(s[--x] ^ '.'))
n/=pow(radix,s.size()-1-x), y+= s.size()-x;
else
n+=( (s[x]- (s[x]<='9' ? '0':'0'+7) ) * pow(radix,s.size()-1-x - y) );
return n;
}
int main(){
std::cout<<_string_to_double("10.A",16)<<std::endl;//Prints 16.625
std::cout<<_string_to_double("1001.1",2)<<std::endl;//Prints 9.5
std::cout<<_string_to_double("123.4",10)<<std::endl;//Prints 123.4
return 0;
}

how to convert a hexadecimal string to a corresponding integer in c++?

i have a unicode mapping stored in a file.
like this line below with tab delimited.
a 0B85 0 0B85
second column is a unicode character. i want to convert that to 0x0B85 which is to be stored in int variable.
how to do it?
You've asked for C++, so here is the canonical C++ solution using streams:
#include <iostream>
int main()
{
int p;
std::cin >> std::hex >> p;
std::cout << "Got " << p << std::endl;
return 0;
}
You can substitute std::cin for a string-stream if that's required in your case.
You could use strtol, which can parse numbers into longs, which you can then assign to your int. strtol can parse numbers with any radix from 2 to 36 (i.e. any radix that can be represented with alphanumeric charaters).
For example:
#include <cstdlib>
using namespace std;
char *token;
...
// assign data from your file to token
...
char *err; // points to location of error, or final '\0' if no error.
int x = strtol(token, &err, 16); // convert hex string to int

atoi() conversion error

atoi() is giving me this error:
error C2664: 'atoi' : cannot convert parameter 1 from 'char' to 'const char *'
Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
from this line:
int pid = atoi( token.at(0) );
where token is a vector
how can i go around this?
token.at(0) is returning a single char, but atoi() is expecting a string (a pointer to a char.) Either convert the single character to a string, or to convert a single digit char into the number it represents you can usually* just do this:
int pid = token.at(0) - '0';
* The exception is when the charset doesn't encode digits 0-9 in order which is extremely rare.
You'll have to create a string:
int pid = atoi(std::string(1, token.at(0)).c_str());
... assuming that token is a std::vector of char, and using std::string's constructor that accepts a single character (and the number of that character that the string will contain, one in this case).
Your example is incomplete, as you don't say the exact type of the vector. I assume it is std::vector<char> (that, perhaps, you filled with each char from a C string).
My solution would be to convert it again on char *, which would give the following code:
void doSomething(const std::vector & token)
{
char c[2] = {token.at(0), 0} ;
int pid = std::atoi(c) ;
}
Note that this is a C-like solution (i.e., quite ugly in C++ code), but it remains efficient.
const char tempChar = token.at(0);
int tempVal = atoi(&tempChar);
stringstream ss;
ss << token.at(0);
int pid = -1;
ss >> pid;
Example:
#include <iostream>
#include <sstream>
#include <vector>
int main()
{
using namespace std;
vector<char> token(1, '8');
stringstream ss;
ss << token.at(0);
int pid = -1;
ss >> pid;
if(!ss) {
cerr << "error: can't convert to int '" << token.at(0) << "'" << endl;
}
cout << pid << endl;
return 0;
}