Unexpected result of ++((unsigned)x), x is uint8_t? - c

Why doesn't this piece of code result in y == 0x100?
uint8_t x = 0xff;
unsigned y = ++((unsigned)x);
Check it out for yourself here: http://codepad.org/dmsmrtsg

The code you posted is invalid form the point of view of C language. The result of any cast in C is an rvalue. It cannot be used as an argument of ++. Operator ++ requires an lvalue argument. I.e. expression ++((unsigned) x) is non-compilable in standard C language.
What you actually observe in this case is GCC's "generalized lvalues" extension
http://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/Lvalues.html
Per that extension (and contrary to the standard C), a cast applied to an lvalue produces an lvalue. When you attempt to write something into the resultant "generalized" lvalue, the value being written is converted twice: it is first converted to the type specified by the explicit cast, and then the intermediate result is converted again to the type of recipient object. The final result is placed into the recipient object.
For example, if with your x you do
(unsigned) x = 0x100;
it will be actually interpreted by GCC as
x = (uint8_t) (unsigned) 0x100;
and the final value of x will be 0.
And this is exactly what happens in your example. In GCC your
++((unsigned) x)
is equivalent to
(unsigned) x = (unsigned) x + 1;
which is in turn interpreted by GCC as
x = (uint8_t) (unsigned) ((unsigned) x + 1);
This is why you get 0 in x as the result, and that is the 0 that then gets assigned to your y.
This extension is referred to as deprecated by GCC docs.

To start this is not valid C code, I don't know how you got it to compile, but your link does show an output, so I'll try to explain what's happening based on this one major assumption:
I guess with this line unsigned y = ++((unsigned x)); the second unsigned is being dropped by your compiler, hence why you're able to build.
So, Assuming that...
uint8_t x = 0xff; // 8 bit value, max is 255(10) or 0xFF(16)
unsigned y = ++((unsigned)x);
Now x has the max value already for its type. You want to know why if we +1 via ++, y doesn't get value of 0x100.
x is 8 bit, typecasting it doesn't change the fact that it's 8 bit. So when we say:
++x
We're incrementing x (x=x+1). So we have an unsigned 8 bit value, at the max and add 1 to it, now it's wrapped around to 0. So y will get 0.
If you wanted this to work you could do something like:
int main(void)
{
unsigned char x = 0xFF; //I'm using char because it's 8 bit too
unsigned int y = 1+x; //no need to typecast, we're already unsigned
printf("%#x %#x\n", x, y);
return 0;
}
Now you'll get the expected values (x==0xFF and y==0x100)

Try this:
uint8_t x = 0xff;
unsigned y = ((unsigned)x) + 1;
It will come out as you expect, because (unsigned) x is now the two-byte value 0x0100.
Now try this:
uint8_t x = 0xff;
++x;
The value of 0xff wraps around to 0x00.

I put in some little transparency code into your excerpt and it explains everything.
#include <stdio.h>
#include <stdint.h> // not needed
int main(void) {
uint8_t x = 0xff;
printf("%d\n", sizeof(x));
unsigned y = ++((unsigned)x);
printf("%d\n", sizeof(y));
printf("0x%x\n", y);
printf("%d\n", sizeof(y));
return 0;
}
and the output is
1 // size of x
4 // size of y before computation
0x100 // computed value of y from your code
4 // size of y after computation
First thing to notice is that the sizeof(y) stays constant across computation.
From the outputs,
uint8_t = 1 byte
unsigned = 4 bytes
When you do a cast in C, think of it as an implicit call to realloc which says: "take this data I have from its block, increase (or decrease) its size in memory to the size I want to cast it to, then return the same data in a new block.
And from our sizes, unsigned will have enough space to fit the result of the computation from a one-byte operation.
Re-explainng your code in byte-level detail,
x = 11111111 = 0xff (in a byte)
(unsigned)x = 00000000000000000000000011111111 = 0xff (in a word)
++((unsigned)x) = 00000000000000000000000100000000 = 0x100

Related

Bitwise operation in character

I am curious about a behavior of bit-wise operator of C on Character.
#include <stdio.h>
int main()
{
int x = 108;
x = x<<1;
printf("%d\n", x);
char y = 108;
y = y<<1;
printf("%d", y);
//printf("%d", y<<1);
return 0;
}
Here, if I pass like this, y = y<<1, it's output was -40 and when I print it directly like,
printf("%d", y<<1);
it's output was 216.
How I can simulate it?
Note that there is really no << operation on char types - the operands of << are promoted to (at least) int types, and the result is, similarly, an int.
So, when you do y = y << 1, you are truncating the int result of the operation to a (signed) char, which leaves the most significant bit (the sign bit) set, so it is interpreted as a negative value.
However, when you pass y << 1 directly to printf, the resulting int is left unchanged.
y<<1 produces an int. To get -40, you were implicitly casting it to a char. In your printf case, you'll need to do the cast explicitly: (char)(y<<1)

C - fail to convert unsigned char array to double

I would like to convert a unsigned char array to double in C. I tried many way to do so but still wrongly converted to 0.00000.
union {
double longtitude;
unsigned char bytes[sizeof(double)];
}u;
unsigned char * receive_buffer = malloc(65536);
int recv = recv(fd,receive_buffer,65536,0);
// the buffer should has 8 byte value {40 5c 80 23 8d a3 c2 12}
memcpy(&u.bytes,receive_buffer,sizeof(double)); // copy to char array
for ( int i=8;i>=0;i--){
u.longtitude = u.bytes[i];
}
printf("%lf",u.longtitude); // the result is 0.000000 / the expected result should be 114.00217
I got the result of '0.000000' from above code that I found from internet. How can I convert the char array to double? What's wrong in above code?
UPDATE
I added more specific code above. I have checked the contents of the receive_buffer and it contains the value in the above comment. The u.bytes correctly gets a value from the buffer via memcpy. The union and for loop part is the way I found from other similar questions. I tried it, but got result = 0.000000. Sorry about the unclear code posted and problem stated before; I am quite new to C language.
Delete the for loop.
The memcpy copies the bytes from the buffer into the bytes array of the union. Those are the same bytes used for the longitude member, so they are already in place. You do not need the for loop to copy those bytes, and it was incorrectly writing the values of the bytes into the value of the double rather than into the bytes that represent the value. Also, the loop index was wrong, as it was using 8 in the first iteration, but the bytes in an eight-byte object are indexed 0 to 7.
More than that, in C, you can modify the bytes that repesent an object with either a union or a memcpy. You do not need both. After the recv, this suffices:
double longitude;
memcpy(&longitude, receive_buffer, sizeof longitude);
I expect you could even do the recv directly into &longitude.
Remove the for loop entirely. I'm not sure what your intent in having it there is, but it undoes (or rather just clobbers) the work you just did.
Based on your update and the expected value of 114.00217, the issue is endian-ness. Whatever machine you are getting the value from does not have the same endianess as your machine. So after converting to double, swap endianess.
// endian_swap() function taken from https://stackoverflow.com/a/21507710/669576
// I modified to work with double
double endian_swap(double d)
{
long x = *(long *)&d;
x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8;
return *(double *)&x;
}
int main(void) {
unsigned char s[] = {0x40,0x5c,0x80,0x23,0x8d,0xa3,0xc2,0x12};
double d;
// Just copy - no union needed
memcpy(&d, s, sizeof(d));
// Swap endianess
d = endian_swap(d);
printf("%lf\n", d);
return 0;
}
Output: 114.002170
I don't do a lot of network programming, but I believe the ntohl() function is used for this. However, I don't know if there is a 64-bit version.
Update: Also, you can use htobe64() (Thanks to #Stargateur):
#include <endian.h>
int main(void) {
unsigned char s[] = {0x40,0x5c,0x80,0x23,0x8d,0xa3,0xc2,0x12};
// htobe64() expects a long, so use that first
long l;
memcpy(&l, s, sizeof(l));
l = htobe64(l);
// Then copy the swapped long bits to a double
double d;
memcpy(&d, &l, sizeof(d));
printf("%lf\n", d);
return 0;
}

function to convert float to int (huge integers)

This is a university question. Just to make sure :-) We need to implement (float)x
I have the following code which must convert integer x to its floating point binary representation stored in an unsigned integer.
unsigned float_i2f(int x) {
if (!x) return x;
/* get sign of x */
int sign = (x>>31) & 0x1;
/* absolute value of x */
int a = sign ? ~x + 1 : x;
/* calculate exponent */
int e = 0;
int t = a;
while(t != 1) {
/* divide by two until t is 0*/
t >>= 1;
e++;
};
/* calculate mantissa */
int m = a << (32 - e);
/* logical right shift */
m = (m >> 9) & ~(((0x1 << 31) >> 9 << 1));
/* add bias for 32bit float */
e += 127;
int res = sign << 31;
res |= (e << 23);
res |= m;
/* lots of printf */
return res;
}
One problem I encounter now is that when my integers are too big then my code fails. I have this control procedure implemented:
float f = (float)x;
unsigned int r;
memcpy(&r, &f, sizeof(unsigned int));
This of course always produces the correct output.
Now when I do some test runs, this are my outputs (GOAL is what It needs to be, result is what I got)
:!make && ./btest -f float_i2f -1 0x80004999
make: Nothing to be done for `all'.
Score Rating Errors Function
x: [-2147464807] 10000000000000000100100110011001
sign: 1
expone: 01001110100000000000000000000000
mantis: 00000000011111111111111101101100
result: 11001110111111111111111101101100
GOAL: 11001110111111111111111101101101
So in this case, a 1 is added as the LSB.
Next case:
:!make && ./btest -f float_i2f -1 0x80000001
make: Nothing to be done for `all'.
Score Rating Errors Function
x: [-2147483647] 10000000000000000000000000000001
sign: 1
expone: 01001110100000000000000000000000
mantis: 00000000011111111111111111111111
result: 11001110111111111111111111111111
GOAL: 11001111000000000000000000000000
Here 1 is added to the exponent while the mantissa is the complement of it.
I tried hours to look ip up on the internet plus in my books etc but I can't find any references to this problem. I guess It has something to do with the fact that the mantissa is only 23 bits. But how do I have to handle it then?
EDIT: THIS PART IS OBSOLETE THANKS TO THE COMMENTS BELOW. int l must be unsigned l.
int x = 2147483647;
float f = (float)x;
int l = f;
printf("l: %d\n", l);
then l becomes -2147483648.
How can this happen? So C is doing the casting wrong?
Hope someone can help me here!
Thx
Markus
EDIT 2:
My updated code is now this:
unsigned float_i2f(int x) {
if (x == 0) return 0;
/* get sign of x */
int sign = (x>>31) & 0x1;
/* absolute value of x */
int a = sign ? ~x + 1 : x;
/* calculate exponent */
int e = 158;
int t = a;
while (!(t >> 31) & 0x1) {
t <<= 1;
e--;
};
/* calculate mantissa */
int m = (t >> 8) & ~(((0x1 << 31) >> 8 << 1));
m &= 0x7fffff;
int res = sign << 31;
res |= (e << 23);
res |= m;
return res;
}
I also figured out that the code works for all integers in the range -2^24, 2^24. Everything above/below sometimes works but mostly doesn't.
Something is missing, but I really have no idea what. Can anyone help me?
The answer printed is absolutely correct as it's totally dependent on the underlying representation of numbers being cast. However, If we understand the binary representation of the number, you won't get surprised with this result.
To understand an implicit conversion is associated with the assignment operator (ref C99 Standard 6.5.16). The C99 Standard goes on to say:
6.3.1.4 Real floating and integer
When a finite value of real floating type is converted to an integer type other than _Bool, the fractional part is discarded (i.e., the value is truncated toward zero). If the value of the integral part cannot be represented by the integer type, the behavior is undefined.
Your earlier example illustrates undefined behavior due to assigning a value outside the range of the destination type. Trying to assign a negative value to an unsigned type, not from converting floating point to integer.
The asserts in the following snippet ought to prevent any undefined behavior from occurring.
#include <limits.h>
#include <math.h>
unsigned int convertFloatingPoint(double v) {
double d;
assert(isfinite(v));
d = trunc(v);
assert((d>=0.0) && (d<=(double)UINT_MAX));
return (unsigned int)d;
}
Another way for doing the same thing, Create a union containing a 32-bit integer and a float. The int and float are now just different ways of looking at the same bit of memory;
union {
int myInt;
float myFloat;
} my_union;
my_union.myInt = 0x BFFFF2E5;
printf("float is %f\n", my_union.myFloat);
float is -1.999600
You are telling the compiler to take the number you have (large integer) and make it into a float, not to interpret the number AS float. To do that, you need to tell the compiler to read the number from that address in a different form, so this:
myFloat = *(float *)&myInt ;
That means, if we take it apart, starting from the right:
&myInt - the location in memory that holds your integer.
(float *) - really, I want the compiler use this as a pointer to float, not whatever the compiler thinks it may be.
* - read from the address of whatever is to the right.
myFloat = - set this variable to whatever is to the right.
So, you are telling the compiler: In the location of (myInt), there is a floating point number, now put that float into myFloat.

How to get float in bytes?

I am using the HIDAPI to send some data to a USB device. This data can be sent only as byte array and I need to send some float numbers inside this data array. I know floats have 4 bytes. So I thought this might work:
float f = 0.6;
char data[4];
data[0] = (int) f >> 24;
data[1] = (int) f >> 16;
data[2] = (int) f >> 8;
data[3] = (int) f;
And later all I had to do is:
g = (float)((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | (data[3]) );
But testing this shows me that the lines like data[0] = (int) f >> 24; returns always 0. What is wrong with my code and how may I do this correctly (i.e. break a float inner data in 4 char bytes and rebuild the same float later)?
EDIT:
I was able to accomplish this with the following codes:
float f = 0.1;
unsigned char *pc;
pc = (unsigned char*)&f;
// 0.6 in float
pc[0] = 0x9A;
pc[1] = 0x99;
pc[2] = 0x19;
pc[3] = 0x3F;
std::cout << f << std::endl; // will print 0.6
and
*(unsigned int*)&f = (0x3F << 24) | (0x19 << 16) | (0x99 << 8) | (0x9A << 0);
I know memcpy() is a "cleaner" way of doing it, but this way I think the performance is somewhat better.
You can do it like this:
char data[sizeof(float)];
float f = 0.6f;
memcpy(data, &f, sizeof f); // send data
float g;
memcpy(&g, data, sizeof g); // receive data
In order for this to work, both machines need to use the same floating point representations.
As was rightly pointed out in the comments, you don't necessarily need to do the extra memcpy; instead, you can treat f directly as an array of characters (of any signedness). You still have to do memcpy on the receiving side, though, since you may not treat an arbitrary array of characters as a float! Example:
unsigned char const * const p = (unsigned char const *)&f;
for (size_t i = 0; i != sizeof f; ++i)
{
printf("Byte %zu is %02X\n", i, p[i]);
send_over_network(p[i]);
}
In standard C is guaranted that any type can be accessed as an array of bytes.
A straight way to do this is, of course, by using unions:
#include <stdio.h>
int main(void)
{
float x = 0x1.0p-3; /* 2^(-3) in hexa */
union float_bytes {
float val;
unsigned char bytes[sizeof(float)];
} data;
data.val = x;
for (int i = 0; i < sizeof(float); i++)
printf("Byte %d: %.2x\n", i, data.bytes[i]);
data.val *= 2; /* Doing something with the float value */
x = data.val; /* Retrieving the float value */
printf("%.4f\n", data.val);
getchar();
}
As you can see, it is not necessary at all to use memcpy or pointers...
The union approach is easy to understand, standard and fast.
EDIT.
I will explain why this approach is valid in C (C99).
[5.2.4.2.1(1)] A byte has CHAR_BIT bits (an integer constant >= 8, in almost cases is 8).
[6.2.6.1(3)] The unsigned char type uses all its bits to represent the value of the object, which is an nonnegative integer, in a pure binary representation. This means that there are not padding bits or bits used for any other extrange purpouse. (The same thing is not guaranted for signed char or char types).
[6.2.6.1(2)] Every non-bitfield type is represented in memory as a contiguous sequence of bytes.
[6.2.6.1(4)] (Cited) "Values stored in non-bit-field objects of any other object type consist of n × CHAR_BIT bits, where n is the size of an object of that type, in bytes. The value may be copied into an object of type unsigned char [n] (e.g., by memcpy); [...]"
[6.7.2.1(14)] A pointer to a structure object (in particular, unions), suitably converted, points to its initial member. (Thus, there is no padding bytes at the beginning of a union).
[6.5(7)] The content of an object can be accessed by a character type:
An object shall have its stored value accessed only by an lvalue expression that has one of
the following types:
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the effective type of the
object,
— a type that is the signed or unsigned type corresponding to a qualified version of the
effective type of the object,
— an aggregate or union type that includes one of the aforementioned types among its
members (including, recursively,amember of a subaggregate or contained union), or
— a character type
More information:
A discussion in google groups
Type-punning
EDIT 2
Another detail of the standard C99:
[6.5.2.3(3) footnote 82] Type-punning is allowed:
If the member used to access the contents of a union object is not the same as the member last used to
store a value in the object, the appropriate part of the object representation of the value is reinterpreted
as an object representation in the new type as described in 6.2.6 (a process sometimes called "type
punning"). This might be a trap representation.
The C language guarantees that any value of any type¹ can be accessed as an array of bytes. The type of bytes is unsigned char. Here's a low-level way of copying a float to an array of bytes. sizeof(f) is the number of bytes used to store the value of the variable f; you can also use sizeof(float) (you can either pass sizeof a variable or more complex expression, or its type).
float f = 0.6;
unsigned char data[sizeof(float)];
size_t i;
for (i = 0; i < sizeof(float); i++) {
data[i] = (unsigned char*)f + i;
}
The functions memcpy or memmove do exactly that (or an optimized version thereof).
float f = 0.6;
unsigned char data[sizeof(float)];
memcpy(data, f, sizeof(f));
You don't even need to make this copy, though. You can directly pass a pointer to the float to your write-to-USB function, and tell it how many bytes to copy (sizeof(f)). You'll need an explicit cast if the function takes a pointer argument other than void*.
int write_to_usb(unsigned char *ptr, size_t size);
result = write_to_usb((unsigned char*)f, sizeof(f))
Note that this will work only if the device uses the same representation of floating point numbers, which is common but not universal. Most machines use the IEEE floating point formats, but you may need to switch endianness.
As for what is wrong with your attempt: the >> operator operates on integers. In the expression (int) f >> 24, f is cast to an int; if you'd written f >> 24 without the cast, f would still be automatically converted to an int. Converting a floating point value to an integer approximates it by truncating or rounding it (usually towards 0, but the rule depends on the platform). 0.6 rounded to an integer is 0 or 1, so data[0] is 0 or 1 and the others are all 0.
You need to act on the bytes of the float object, not on its value.
¹ Excluding functions which can't really be manipulated in C, but including function pointers which functions decay to automatically.
Assuming that both devices have the same notion of how floats are represented then why not just do a memcpy. i.e
unsigned char payload[4];
memcpy(payload, &f, 4);
the safest way to do this, if you control both sides is to send some sort of standardized representation... this isn't the most efficient, but it isn't too bad for small numbers.
hostPort writes char * "34.56\0" byte by byte
client reads char * "34.56\0"
then converts to float with library function atof or atof_l.
of course that isn't the most optimized, but it sure will be easy to debug.
if you wanted to get more optimized and creative, first byte is length then the exponent, then each byte represents 2 decimal places... so
34.56 becomes char array[] = {4,-2,34,56}; something like that would be portable... I would just try not to pass binary float representations around... because it can get messy fast.
It might be safer to union the float and char array. Put in the float member, pull out the 4 (or whatever the length is) bytes.

converting byte array to double - c

I'm trying to get the numerical (double) value from a byte array of 16 elements, as follows:
unsigned char input[16];
double output;
...
double a = input[0];
distance = a;
for (i=1;i<16;i++){
a = input[i] << 8*i;
output += a;
}
but it does not work.
It seems that the temporary variable that contains the result of the left-shift can store only 32 bits, because after 4 shift operations of 8 bits it overflows.
I know that I can use something like
a = input[i] * pow(2,8*i);
but, for curiosity, I was wondering if there's any solution to this problem using the shift operator...
Edit: this won't work (see comment) without something like __int128.
a = input[i] << 8*i;
The expression input[i] is promoted to int (6.3.1.1) , which is 32bit on your machine. To overcome this issue, the lefthand operand has to be 64bit, like in
a = (1L * input[i]) << 8*i;
or
a = (long long unsigned) input[i] << 8*i;
and remember about endianness
The problem here is that indeed the 32 bit variables cannot be shifted more than 4*8 times, i.e. your code works for 4 char's only.
What you could do is find the first significant char, and use Horner's law: anxn + an-1n-1 + ... = ((...( anx + an-1 ).x + an-2 ) . x + ... ) + a0 as follows:
char coefficients[16] = { 0, 0, ..., 14, 15 };
int exponent=15;
double result = 0.;
for(int exponent = 15; exp >= 0; --exp ) {
result *= 256.; // instead of <<8.
result += coefficients[ exponent ];
}
In short, No, you can't convert a sequence of bytes directly into a double by bit-shifting as shown by your code sample.
byte, an integer type and double, a floating point type (i.e. not an integer type) are not bitwise compatible (i.e. you can't just bitshift to values of a bunch of bytes into a floating point type and expect an equivalent result.)
1) Assuming the byte array is a memory buffer referencing an integer value, you should be able to convert your byte array into a 128-bit integer via bit-shifting and then convert that resulting integer into a double. Don't forget that endian-issues may come into play depending on the CPU architecture.
2) Assuming the byte array is a memory buffer that contains a 128-bit long double value, and assuming there are no endian issues, you should be able to memcpy the value from the byte array into the long double value
union doubleOrByte {
BYTE buffer[16];
long double val;
} dOrb;
dOrb.val = 3.14159267;
long double newval = 0.0;
memcpy((void*)&newval, (void*)dOrb.buffer, sizeof(dOrb.buffer));
Why not simply cast the array to a double pointer?
unsigned char input[16];
double* pd = (double*)input;
for (int i=0; i<sizeof(input)/sizeof(double); ++i)
cout << pd[i];
if you need to fix endian-ness, reverse the char array using the STL reverse() before casting to a double array.
Have you tried std::atof:
http://www.cplusplus.com/reference/clibrary/cstdlib/atof/
Are you trying to convert a string representation of a number to a real number? In that case, the C-standard atof is your best friend.
Well based off of operator precedence the right hand side of
a = input[i] << 8*i;
gets evaluated before it gets converted to a double, so you are shifting input[i] by 8*i bits, which stores its result in a 32 bit temporary variable and thus overflows. You can try the following:
a = (long long unsigned int)input[i] << 8*i;
Edit: Not sure what the size of a double is on your system, but on mine it is 8 bytes, if this is the case for you as well the second half of your input array will never be seen as the shift will overflow even the double type.

Resources