cast from 'char*' to 'int' loses precision - c++

am having a problem converting a char* into am int in a 64 bit machine .
i know the problem is on 64 bit sizeof(char*) is 8 and sizeof(int) is 4.
here's the code :
void books::update()
{
int b_id[100],qty[100],i=0,max;
stmt.str("");
stmt<<" Select book_id,qty from purchase where recieves ='T' and inv IS NULL;";
query=stmt.str();
q =query.c_str();
mysql_query(conn,q);
res_set=mysql_store_result(conn);
stmt.str("");
stmt<<" Update purchases set inv=1 where recieves ='T' and inv is NULL";
query=stmt.str();
q=query.c_str();
mysql_query(conn,q);
while((row=mysql_fetch_row(res_set))!=NULL)
{
b_id[i]=(int)row[0];
qty[i]= (int)row[1];
i++;
}
max=i;
for(i =0;i<max;i++)
{
stmt.str("");
stmt<<" update books set qty ="<< qty[i]<<"where id = "<<b_id[i]<<";";
query= stmt.str();
q= query.c_str();
mysql_query(conn,q);
}
cout<<" The order recieved has been updated .";
}
the bug is in these two lines :
b_id[i]=(int)row[0];
qty[i]= (int)row[1];
i tried to use (long) instead of (int) ,expecting it to convert my int from 4 bytes to 8 bytes and i still got the same error (cast from 'char*' to 'int' loses precision )

The standard library has two fixed width typedefs capable of holding a pointer to void which are defined in <cstdint>:
std::intptr_t // signed
std::uintptr_t // unsigned
However, you do not convert a C string to an integer via a cast. The C string must be interpreted somehow. Example:
#include <sstream>
// ...
// put the two C strings in an istringstream:
std::istringstream is(std::string(row[0]) + ' ' + std::string(row[1]));
// and extract the values
if(is >> b_id[i] >> qty[i]) {
// success
}
Other options are to use std::stoi or
std::strtol. Example:
b_id[i] = std::stoi(row[0]); // may throw std::invalid_argument ...
qty[i] = std::stoi(row[1]); // ... or std::out_of_range

Change int to std::intptr_t everywhere, including the array declarations. You need #include <cstdint> for that.
More info about integer types in C++: https://en.cppreference.com/w/cpp/types/integer

You need a long long, not a long to perform the cast. But I doubt that this will solve your problem at all.

Related

How can i get the first element from an array of character containing float values?

I am trying to get the first element value from array of character containing float.
The character array size is 7, and it's containing two float elements hence size can be assumed 8. I want to get only the first element ignoring anything about 2nd value.
Here is my code-
int main()
{
char cArr[7] = {2.0085,4.52};
char* charPtr = nullptr;
charPtr=cArr;
cout<<"char[0] :"<<*charPtr<<endl;
float* fPtr =(float*)charPtr;
cout<<"char[0] :"<<*fPtr<<endl;
cout<<endl;
}
Here is my output:
g++ b.cpp -o b.exe -std=c++0x
b.cpp: In function 'int main()':
b.cpp:6:29: warning: narrowing conversion of '2.0085000000000002e+0' from 'double' to 'char' inside { } [-Wnarrowing]
char cArr[7] = {2.0085,4.52};
^
b.cpp:6:29: warning: narrowing conversion of '4.5199999999999996e+0' from 'double' to 'char' inside { } [-Wnarrowing]
./b.exe
char[0] :
char[0] :1.43773e-42
I am expecting:
char[0] :2.0085
Any suggestions with the code change?
It seems like what you are trying to make your array hold this:
float fArr[2] = { 2.0085, 4.52 };
char cArr[7];
memcpy(cArr, fArr, 7);
The code you gave does not give you access to the bytes of a float's representation. memcpy will.
However, it's still not allowed to read a float out of the char array through pointer casting. That is a violation of strict aliasing, and results in undefined behavior. To read four bytes from the array and treat them as the representation of a float, you need a second call to memcpy.
Any suggestions with the code change?
You actually want this:
float cArr[2] = { 2.0085, 4.52 };
float *fPtr = cArr;
If I understand your question correct, you have a text string with comma separated decimal point values. Like: "2.0085,4.52"
Now you want to extract the first decimal point value (i.e. "2.0085") and convert it to a float (i.e. like float f = 2.0085).
There are two major problems with your code:
1) The text string initialization is wrong and the char array is too short.
2) You can't do the conversion by casting pointers. You need to call special function that does the conversion (e.g. atof).
One way to do it is like this:
#include <iostream>
#include <cstring>
int main()
{
// Initialize text string with comma seperated decimal point values
char cArr[32] = "2.0085,4.52";
// Extract the first decimal point text string
char* p = std::strtok(cArr, ",");
std::cout << "First text string: " << p << std::endl;
// Convert the text representation to a float representation
float f = std::atof(p);
std::cout << "First float value: " << f << std::endl;
return 0;
}
Output:
First text string: 2.0085
First float value: 2.0085

atoi() - from char to int

char c;
int array[10][10];
while( !plik.eof())
{
getline( plik, text );
int string_l=text.length();
character_controler=false;
for(int i=0; i<string_l; ++i)
{
c=napis.at(i);
if(c==' ') continue;
else if(character_controler==false)
{
array[0][nood]=0;
cout<<"nood: "<<nood<< "next nood "<<c<<endl;
array[1][nood]=atoi(c); // there is a problem
character_controler=true;
}
else if(c==',') character_controler=false;
}
++nood;
}
I have no idea why atoi() doesn't work. The compiler error is:
invalid conversion from `char` to `const char*`
I need to convert c into int.
A char is already implicitly convertible to an int:
array[1][nood] = c;
But if you meant to convert the char '0' to the int 0, you'll have to take advantage of the fact that the C++ standard mandates that the digits are contiguous. From [lex.charset]:
In both the
source and execution basic character sets, the value of each character after 0 in the above list of decimal
digits shall be one greater than the value of the previous.
So you just have to subtract:
array[1][nood] = c - '0';
atoi() expects a const char*, which maps to a c string as an argument, you're passing a simple char. Thus the error, const char* represents a pointer, which is not compatible with a char.
Looks like you need to convert only one character to a numeric value, and in this case you can replace atoi(c) by c-'0', which will give you a number between 0 and 9. However, if your file contains hexadecimals digits, the logic get a little bit more complicated, but not much.

Basics of strtol?

I am really confused. I have to be missing something rather simple but nothing I am reading about strtol() is making sense. Can someone spell it out for me in a really basic way, as well as give an example for how I might get something like the following to work?
string input = getUserInput;
int numberinput = strtol(input,?,?);
The first argument is the string. It has to be passed in as a C string, so if you have a std::string use .c_str() first.
The second argument is optional, and specifies a char * to store a pointer to the character after the end of the number. This is useful when converting a string containing several integers, but if you don't need it, just set this argument to NULL.
The third argument is the radix (base) to convert. strtol can do anything from binary (base 2) to base 36. If you want strtol to pick the base automatically based on prefix, pass in 0.
So, the simplest usage would be
long l = strtol(input.c_str(), NULL, 0);
If you know you are getting decimal numbers:
long l = strtol(input.c_str(), NULL, 10);
strtol returns 0 if there are no convertible characters at the start of the string. If you want to check if strtol succeeded, use the middle argument:
const char *s = input.c_str();
char *t;
long l = strtol(s, &t, 10);
if(s == t) {
/* strtol failed */
}
If you're using C++11, use stol instead:
long l = stol(input);
Alternately, you can just use a stringstream, which has the advantage of being able to read many items with ease just like cin:
stringstream ss(input);
long l;
ss >> l;
Suppose you're given a string char const * str. Now convert it like this:
#include <cstdlib>
#include <cerrno>
char * e;
errno = 0;
long n = std::strtol(str, &e, 0);
The last argument 0 determines the number base you want to apply; 0 means "auto-detect". Other sensible values are 8, 10 or 16.
Next you need to inspect the end pointer e. This points to the character after the consumed input. Thus if all input was consumed, it points to the null-terminator.
if (*e != '\0') { /* error, die */ }
It's also possible to allow for partial input consumption using e, but that's the sort of stuff that you'll understand when you actually need it.
Lastly, you should check for errors, which can essentially only be overflow errors if the input doesn't fit into the destination type:
if (errno != 0) { /* error, die */ }
In C++, it might be preferable to use std::stol, though you don't get to pick the number base in this case:
#include <string>
try { long n = std::stol(str); }
catch (std::invalid_argument const & e) { /* error */ }
catch (std::out_of_range const & e) { /* error */ }
Quote from C++ reference:
long int strtol ( const char * str, char ** endptr, int base );
Convert string to long integer
Parses the C string str interpreting its content as an integral number of the specified base, which is returned as a long int value. If endptr is not a null pointer, the function also sets the value of endptr to point to the first character after the number.
So try something like
long l = strtol(pointerToStartOfString, NULL, 0)
I always use simply strol(str,0,0) - it returns long value. 0 for radix (last parameter) means to auto-detect it from input string, so both 0x10 as hex and 10 as decimal could be used in input string.

Byte from string/int in C++

I'm a beginning user in C++ and I want to know how to do this:
How can I 'create' a byte from a string/int. So for example I've:
string some_byte = "202";
When I would save that byte to a file, I want that the file is 1 byte instead of 3 bytes.
How is that possible?
Thanks in advance,
Tim
I would use C++'s String Stream class <sstream> to convert the string to an unsigned char.
And write the unsigned char to a binary file.
so something like [not real code]
std::string some_byte = "202";
std::istringstream str(some_byte);
int val;
if( !(str >> val))
{
// bad conversion
}
if(val > 255)
{
// too big
}
unsigned char ch = static_cast<unsigned char>(val);
printByteToFile(ch); //print the byte to file.
The simple answer is...
int value = atoi( some_byte ) ;
There are a few other questions though.
1) What size is an int and is it important? (for almost all systems it's going to be more than a byte)
int size = sizeof(int) ;
2) Is the Endianness important? (if it is look in to the htons() / ntohs() functions)
In C++, casting to/from strings is best done using string streams:
#include <sstream>
// ...
std::istringstream iss(some_string);
unsigned int ui;
iss >> ui;
if(!iss) throw some_exception('"' + some_string + "\" isn't an integer!");
unsigned char byte = i;
To write to a file, you use file streams. However, streams usually write/read their data as strings. you will have to open the file in binary mode and write binary, too:
#include <fstream>
// ...
std::ofstream ofs("test.bin", std::ios::binary);
ofs.write( reinterpret_cast<const char*>(&byte), sizeof(byte)/sizeof(char) );
Use boost::lexical_cast
#include "boost/lexical_cast.hpp"
#include <iostream>
int main(int, char**)
{
int a = boost::lexical_cast<int>("42");
if(a < 256 && a > 0)
unsigned char c = static_cast<unsigned char>(a);
}
You'll find the documentation at http://www.boost.org/doc/libs/1_43_0/libs/conversion/lexical_cast.htm
However, if the goal is to save space in a file, I don't think it's the right way to go. How will your program behave if you want to convert "257" into a byte? Juste go for the simplest. You'll work out later any space use concern if it is relevant (thumb rule: always use "int" for integers and not other types unless there is a very specific reason other than early optimization)
EDIT
As the comments say it, this only works for integers, and switching to bytes won't (it will throw an exception).
So what will happen if you try to parse "267"?
IMHO, it should go through an int, and then do some bounds tests, and then only cast into a char. Going through atoi for example will result extreamly bugs prone.

Converting a Char to Its Int Representation

I don't see this an option in things like sprintf().
How would I convert the letter F to 255? Basically the reverse operation of conversion using the %x format in sprintf?
I am assuming this is something simple I'm missing.
char const* data = "F";
int num = int(strtol(data, 0, 16));
Look up strtol and boost::lexical_cast for more details and options.
Use the %x format in sscanf!
The C++ way of doing it, with streams:
#include <iomanip>
#include <iostream>
#include <sstream>
int main() {
std::string hexvalue = "FF";
int value;
// Construct an input stringstream, initialized with hexvalue
std::istringstream iss(hexvalue);
// Set the stream in hex mode, then read the value, with error handling
if (iss >> std::hex >> value) std::cout << value << std::endl;
else std::cout << "Conversion failed" << std::endl;
}
The program prints 255.
You can't get (s)printf to convert 'F' to 255 without some black magic. Printf will convert a character to other representations, but won't change its value. This might show how character conversion works:
printf("Char %c is decimal %i (0x%X)\n", 'F', 'F', 'F');
printf("The high order bits are ignored: %d: %X -> %hhX -> %c\n",
0xFFFFFF46, 0xFFFFFF46, 0xFFFFFF46, 0xFFFFFF46);
produces
Char F is decimal 70 (0x46)
The high order bits are ignored: -186: FFFFFF46 -> 46 -> F
Yeah, I know you asked about sprintf, but that won't show you anything until you do another print.
The idea is that each generic integer parameter to a printf is put on the stack (or in a register) by promotion. That means it is expanded to it's largest generic size: bytes, characters, and shorts are converted to int by sign-extending or zero padding. This keeps the parameter list on the stack in sensible state. It's a nice convention, but it probably had it's origin in the 16-bit word orientation of the stack on the PDP-11 (where it all started).
In the printf library (on the receiving end of the call), the code uses the format specifier to determine what part of the parameter (or all of it) are processed. So if the format is '%c', only 8 bits are used. Note that there may be some variation between systems on how the hex constants are 'promoted'. But if a value greater thann 255 is passed to a character conversion, the high order bits are ignored.