Passing pointer of unsigned int to pointer of long int - c++

I have a sample code which is working properly in 32 bit system, but when I cross compile it for 64-bit system and try to run on 64 bit Machine, it behaves differently.
Can anyone tell me why this is happening?
#include <usr/include/time.h>
#include <sys/time.h>
void func(time_t * inputArg)
{
printf("%ld\n",*inputArg);
}
int main()
{
unsigned int input = 123456;
func((time_t *)&input);
}
Here "time_t" is a type defined in linux system library header file which is of type "long int".
This code is working fine with a 32-bit system but it isn't with 64-bit.
For 64-bit I have tried this:
#include <usr/include/time.h>
#include <sys/time.h>
void func(time_t * inputArg)
{
printf("%ld\n",*inputArg);
}
int main()
{
unsigned int input = 123456;
time_t tempVar = (time_t)input
func(&tempVar);
}
Which is working fine, but I have used the first method in my whole application a number of times. Any alternate solutions would be appreciated.

can anyone tell me why this is happening?
Dereferencing an integer pointer of different size than the type of the pointed object has undefined behaviour.
If the pointed to integer is smaller than the pointers pointed type, you will read unrelated bytes as part of the dereferenced number.
Your fix works because you pass a pointer to an object of proper type, but consider that your input cannot represent all of the values that time_t can.
Best fix is to use the proper type initially. Use time_t as the input.

Your "fixed" code has a cast that lets the compiler convert your unsigned int value to a time_t. Your original code assumes that they're identical.
On your 32-bit system they are identical, so you get lucky. On your 64-bit system you find out what happens when you invoke Undefined Behavior.
In other words, both C and C++ allow you to cast pointers to whatever you want, but it's up to you to make sure such casts are safe.

thank you for response.
Actually I found my mistake when I printed sizeof 'long int' in 32bit machine and 64bit machine.
32bit machine :
sizeof(int) = 32bit & sizeof(long int) = 32 bit & sizeof(long long int) = 64 bit
64bit machine:
sizeof(int) = 32bit & sizeof(long int) = 64 bit & sizeof(long long int) = 64 bit

Related

different casting double type to unsigned long long type result in c++ from windows and linux

I want to get a result from casting double type to usigned long long type in c++. But that code have different result from Windows and Linux.
Here's my code.
#include <iostream>
#include <cmath>
using namespace std;
int main() {
cout << (unsigned long long) pow(10, 18) << endl;
return 0;
}
I just used 'pow' function to get 10 to the 18, and cast it to unsigned long long type. In Windows, It has result of 99999999999999999 (10^18-1), but It has result of 1000000000000000000 (10 ^18) in Linux.
I used MinGW g++ for C++11 compilation in Windows and use g++ in Linux.
What's the reason of this result? Thanks.
The reason is that pow operates on floating-point values, and different implementations can produce values that differ slightly in their low bits. If you need exact integer results, do integer arithmetic.
Contrary to one of the comments in response to the question, converting the result of this call to unsigned long long is perfectly safe (for some sensible meaning of “safe”): unsigned long long can hold the value that this call to pow returns, and the resulting value will be the floating-point result with its fraction discarded.

getting an warning cast to pointer from integer of different size

I am currently working on porting from 32 bit to 64 bit. And I am getting a warning:
cast to pointer from integer of different size
In the following code
AcLogFileWrite(
(FILE *) pOut->pTrace->logFileHandle, /* warning in this line */
outRecord,
outRecordLen);
and prototype of AcLogFileWrite() is
int AcLogFileWrite(
FILE * handle,
char * data,
int bytes);
Here the parameter pOut->pTrace->logFileHandle is of type int.
How can I fix this warning?
You can’t store 64 bits in a 32-bit int. If logFileHandle has to store a pointer, the only integer types that can safely do that are uintptr_t or intptr_t from <stdint.h>. Or you can typedef void*. Since you’re porting to a new ABI anyway, binary compatibility is not an issue and this is a good time to fix it.
If you absolutely cannot change the definition of the type from int, then you must compile under the ILP64 model, in which int, long and void* are all 64 bits wide.
If logFileHandle in fact is a file descriptor getting initialised using e.g. open() you want to use fdopen on it and pass the function's result to AcLogFileWrite().

Why do I get wrong conversion from hex to decimal with strtoul function in Visual Studio compiler?

I am converting a string from hex to decimal. The problem is that in Visual Studio compiler the conversion returns a wrong value. However when I compile the same code in a Mac at the terminal using the g++ compiler, the value is returned correctly.
Why this is happening?
#include <string>
#include <iostream>
using namespace std;
int main()
{
string hex = "412ce69800";
unsigned long n = strtoul( hex.c_str(), nullptr, 16 );
cout<<"The value to convert is: "<<hex<<" hex\n\n";
cout<<"The converted value is: "<<n<<" dec\n\n";
cout<<"The converted value should be: "<<"279926183936 dec\n\n";
return 0;
}
output:
Because in Windows long is a 32-bit type, unlike most Unix/Linux implementations which use LP64 memory model in which long is 64 bits. The number 412ce69800 has 39 bits and inherently it can't be stored in a 32-bit type. Read compiler warnings and you'll know the issue immediately
C standard only requires long to have at least 32 bits. C99 added a new long long type with at least 64 bits, and that's guaranteed in all platforms. So if your value is in 64-bit type's range, use unsigned long long or uint64_t/uint_least64_t and strtoull instead to get the correct value.

c++ portable conversion of long to double

I need to accurately convert a long representing bits to a double and my soluton shall be portable to different architectures (being able to be standard across compilers as g++ and clang++ woulf be great too).
I'm writing a fast approximation for computing the exp function as suggested in this question answers.
double fast_exp(double val)
{
double result = 0;
unsigned long temp = (unsigned long)(1512775 * val + 1072632447);
/* to convert from long bits to double,
but must check if they have the same size... */
temp = temp << 32;
memcpy(&result, &temp, sizeof(temp));
return result;
}
and I'm using the suggestion found here to convert the long into a double. The issue I'm facing is that whereas I got the following results for int values in [-5, 5] under OS X with clang++ and libc++:
0.00675211846828461
0.0183005779981613
0.0504353642463684
0.132078289985657
0.37483024597168
0.971007823944092
2.7694206237793
7.30961990356445
20.3215942382812
54.8094177246094
147.902587890625
I always get 0 under Ubuntu with clang++ (3.4, same version) and libstd++. The compiler there even tells me (through a warning) that the shifting operation can be problematic since the long has size equal or less that the shifting parameter (indicating that longs and doubles have not the same size probably)
Am I doing something wrong and/or is there a better way to solve the problem being as more compatible as possible?
First off, using "long" isn't portable. Use the fixed length integer types found in stdint.h. This will alleviate the need to check for the same size, since you'll know what size the integer will be.
The reason you are getting a warning is that left shifting 32 bits on the 32 bit intger is undefined behavior. What's bad about shifting a 32-bit variable 32 bits?
Also see this answer: Is it safe to assume sizeof(double) >= sizeof(void*)? It should be safe to assume that a double is 64bits, and then you can use a uint64_t to store the raw hex. No need to check for sizes, and everything is portable.

convert int[2] to long

I have an int[2] representation of a long int in a 32 bit machine and want to convert it to long on 64bit machine. is there a safe architecture independent way of doing this conversion?
The source machine is 32bit and an int is 32bits. Destination machine is 64bit and the long long type is definitely 64bits.
can I do the following?
long i;
int j[2];
#ifdef LITTLEENDIAN
j[1] = *(int*)(&i);
j[0] = *(((int*)(&i))+1)
#else
j[0] = *(int*)(&i);
j[1] = *(((int*)(&i))+1)
#endif
If the above is incorrect, then what is the best and safest way for this? I am sure this would have been asked previously, but I didn't find a clean answer.
Thanks
I have an int[2] representation of a long int in a 32 bit machine and want to convert it to long on 64bit machine. is there a safe architecture independent way of doing this conversion?
Not really. Because apart from endianness, the sizes of the two datatypes may vary as well. On some popular platforms, int and long have the same size (both 32 bits)
Ultimately, it depends on how you created your int[2] representation. Whatever you did to create that int array has to be reversed in order to get a valid long out of it.
One approach which will work in practice (but is, technically speaking, undefined behavior), is to place both in a union:
union {
int i2[2];
long l;
} u;
Now you can simply write to u.i2 and read from u.l. The C++ standard technically doesn't allow this (it is undefined behavior), but it is such a common trick that major compilers explicitly support it anyway.
However, a better approach might be to use a char[] instead of int[], because char's are explicitly allowed to alias other types.
If you are sure of having 32-bit integer and 64-bit then you can use union concept.
union Convert
{
long i;
int j[2];
};
The width concern could be addressed by using boost::uint64_t on both machines.
http://www.boost.org/doc/libs/1_46_1/libs/integer/doc/html/boost_integer/cstdint.html#boost_integer.cstdint.exact_width_integer_types