Variable size allocated during assign operation - c

int main()
{
int a;
char b,c;
b=0x32;
c=0x24;
a=b*256+c;
printf("a=%#x\n",a);
return 0;
}
Output:
a=0x3224
Size of b is 1 byte; b*256 is a overflow for a char variable. Does the compiler allocate 2 different 16 bit registers for this operation? int is 16 bits over here.

In the multiplication by the literal 256 on the following line, the char is promoted to an int before multiplication.
a = b*256 + c;

No it doesn't overflow. Instead the contents of variable b (as well as c) are promoted to the type int.

C language never performs arithmetic computations withing the domain of char, short or any other type that is smaller than int. Operands of arithmetic operators are promoted to int before the actual computations begin (assuming int can represent all values of the original type). So, your
a = b * 256 + c;
is actually interpreted by the compiler as
a = (int) b * 256 + (int) c;
In other words, expression b *= 256 would indeed overflow a char variable on assignment back to b, but expression b * 256 does not overflow by itself.

Related

Float to Binary in C

I am asked to convert a float number into a 32 bit unsigned integer. I then have to check if all the bits are zero but I am having trouble with this. Sorry I am new to C
This is what I am doing
float number = 12.5;
// copying number into a 32-bit unsigned int
unsigned int val_number = *((unsigned int*) &number);
At this point I'm very confused on how to check if all bits are zero.
I think I need to loop through all the bits but I don't know how to do that.
To copy the bytes of a 32-bit float to an integer, best to copy to an integer type that is certainly 32-bit. unsigned may be less, same or more than 32-bits.
#include <inttypes.h>
float number = 12.5;
uint32_t val_number32; // 32-bit type
memcpy(&val_number32, &number, sizeof val_number32);
Avoid the cast and assign. It leads to aliasing problems with modern compilers #Andrew.
"... need cast the addresses of a and b to type (unsigned int *) and then dereference the addresses" reflects a risky programing technique.
To test if the bits of the unsigned integer are all zero, simply test with the constant 0.
int bit_all_zero = (val_number32 == 0);
An alternative is to use a union to access the bytes from 2 different encodings.
union {
float val_f;
uint32_t val_u;
} x = { .val_f = 12.5f };
int bit_all_zero = (x.val_u == 0);
Checking if all the bits are zero is equivalent to checking if the number is zero.
So it would be int is_zero = (val_number == 0);

summing unsigned and signed ints, same or different answer?

If I have the following code in C
int main()
{
int x = <a number>
int y = <a number>
unsigned int v = x;
unsigned int w = y;
int ssum = x * y;
unsigned int usum = v * w;
printf("%d\n", ssum);
printf("%d\n", usum);
if(ssum == usum){
printf("Same\n");
} else {
printf("Different\n");
}
return 0;
}
Which would print the most? Would it be equal since signed and unsigned would produce the same result, then if you have a negative like -1, when it gets assigned to int x it becomes 0xFF, and if you want to do -1 + (-1), if you do it the signed way to get -2 = 0xFE, and since the unsigned variables would be set to 0xFF, if you add them you would still get 0xFE. And the same holds true for 2 + (-3) or -2 + 3, in the end the hexadecimal values are identical. So in C is that what's looked at when it sees signedSum == unsignedSum? It doesnt care that one is actually a large number and the other is -2, as long at the 1's and 0's are the same?
Are there any values that would make this not true?
The examples you have given are incorrect in C. Also, converting between signed and unsigned types is not required to preserve bit patterns (the conversion is by value), although with some representations bit patterns are preserved.
There are circumstances where the result of operations will be the same, and circumstances where the result will differ.
If the (actual) sum of adding two ints would overflow an int
(i.e. value outside range that an int can represent) the result is
undefined behaviour. Anything can happen at that point (including
the program terminating abnormally) - subsequently converting to an unsigned doesn't change anything.
Converting an int with negative value to unsigned int uses modulo
arithmetic (modulo the maximum value that an unsigned can
represent, plus one). That is well defined by the standard, but
means -1 (type int) will convert to the maximum value that an
unsigned can represent (i.e. UINT_MAX, an implementation defined
value specified in <limits.h>).
Similarly, adding two variables of type unsigned int always uses
modulo arithmetic.
Because of things like this, your question "which would produce the most?" is meaningless.

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 char to int [C]

I have a char byte that I want to convert to an int. Basically I am getting the value (which is 0x13) from a file using the fopen command and storing it into a char buffer called buff.
I am doing the following:
//assume buff[17] = 0x13
v->infoFrameSize = (int)buff[17] * ( 128^0 );
infoFrameSize is a type int that is stored in a structure called 'v'.
The value I get for v->infoFrameSize is 0x00000980. Should this be 0x00000013?
I tried taking out the multiply by 128 ^ 0 and I get the correct output:
v->infoFrameSize = 0x00000013
Any info or suggested reading material on what is happening here would be great. Thanks!
^ is bitwise xor operation, not exponentiation.
Operator ^ in C does bit operation - XOR.
128 xor 0 equals 128.
In C 128 ^ 0 equates the bitwise XOR of 128 and 0, it doesn't raise 128 to the power of 0 (which is just 1).
A char is simply an integer consisting of a single byte, to "convert" it to an int (which isn't really converting, you're just storing the byte into a larger data type) you do:
char c = 5;
int i = (int)c
tada.
There is no point in the ^0 term. Anything xor'd with zero remains unchanged (so 128^0 is 128).
The value you get is correct; when you multiply 0x13 (aka 19) by 128 (aka 0x80), you get 0x0980 (aka 2432).
Why would you expect the assignment to ignore the multiplication?
128^0 is not doing what you think it does.
cout << (128^0)
returns 128.
Try pow(128,0). Then, add the following to the top of your code:
#include <math.h>
Also, note that pow always returns a float. So you'll need to cast your final answer to an int. So:
(int)(buff[17] * pow(128,0));
To convert a char to an int, you merely cast it:
char c = ...;
int x = (int) c;
K&R would have you read the one byte from the file using getc() and store it directly into an int which eliminates any issues you might be seeing. However, if you are reading from the file into an array of bytes, simply cast to int as follows:
v->infoFrameSize = (int)buff[17];
I'm not sure why you're multiplying by 128^0.
The only problem I know of when converting from char to int is that char can be signed or unsigned, depending on the platform. If it happens to be signed, a big positive number stored inside a char may end up being considered as negative. When you will print it, it will either be a negative number or an abnormally big number (if you print it as an unsigned integer).
The solution is simply to use signed char or unsigned char explicitly in cases like this one.
"^" is a bitwise XOR Operation, if you want to do an exponent use
pow(128,0);
Why are you multiplying by one?
You can convert from a char to an int by simply defining an int and setting it like so:
char x = 0x13;
int y;
y = (int)x;

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