anshu
anshu

Reputation: 665

int array to struct array in C

I am using Code-Blocks with the mingw GCC compiler for windows to code my program in C. I have a function defined where the input is an array of type int. I have another struct defined as

typedef struct {
float re;
float im;
}complex_float;

I want to convert the int type array to a complex_float type array as I need to process the data in the complex_float format. I am using the following pointer method to do the conversion

complex_float *comSig = (complex_float *) sigbuf;

where sigbif is an int pointer pointing to the start address of the integer array.

But when i do a printf("%f",comSig[0].re); I am getting some garbage values like -1.#QNAN0.

I have used this technique for data conversion between arrays a number of times on LINUX and it works. Is this a problem related to the mingw compiler not working clearly or is it related to the fact that I am using an incorrect method for converting an int array to struct array.

Upvotes: 2

Views: 2292

Answers (4)

mcmlxxxvi
mcmlxxxvi

Reputation: 1409

The answers so far have pointed out most of the problems with your approach, namely explicit value casting, structure alignment, and array of structs vs. int array. I'll add one more point:

int and float types are both of size 4 bytes, I have checked that...

Int and float are represented in a completely different way in-memory.

Integer values are represented in what is known as Two's complement, which allows integers to be added without extra operations and gives a single representation of the number 0:

  • Positive integers are simply converted to base 2. For example, 151 is represented as 00000000 00000000 00000000 10010111(2) = 2^7 + 2^4 + 2^2 + 2^1 + 2^0.
  • Negative integers are represented as the binary representation of their absolute values, which then has all its bits inverted and 1 added to the resultant number. For example, -151 is represented as 11111111 11111111 11111111 01101001(2) (Compare with the positive number).

Single-precision floating points, on the other hand, are represented as what is termed binary32 in the IEEE 754-2008 standard:

  • The first bit is the sign bit: 0 for positive and 1 for negative.
  • The next 8 bits are the exponent, in 2's complement. It is biased: subtract 127 from this value to get the actual exponent.
  • The next 23 bits represent the fractional part of the normalized (having only 1 digit before the decimal point) fraction.

So 151.0 is represented as 01000011 00010111 00000000 00000000, having an exponent of 134 (which is 7 unbiased) and a mantissa of 0.1796875 (which is 1.1796875 because the integral part is implicit).

This is why, if you cast a float * to an int *, which is equivalent to what you have done, you get garbage values when you dereference it later. H2CO3 has pointed out the proper conversion method through the assignment operator.

Upvotes: 0

In C, there is no such conversion functionality. What you do is just a pointer cast.

What happens when you do it:

sigbuf points to an array of integers. When you cast it to (complex_float*) and try to access the real part of the first struct element, you actually access the first integer value of the array but it seems garbage to you because you implicitly casting it to a float value.

Let me illustrate for you, when you have an integer of array size n. Actually you have a sequential data like this:

[int0][int1][int2][int3][int4][int5][int6][int7][int8]...[intN]

When you cast it like this: complex_float *comSig = (complex_float *) sigbuf; Compiler will treat your data like this (Note that now they are treated as float):

[re0][im0][re1][im1][re2][im2][re3][im3][re4][im4]...[re(N/2)][im(N/2)]

So what the cast resulted is just telling compiler that treat the integer data as float, which will result in a seem-garbage output. For the right way to solve your problem, there is another answer provided by H2CO3.

Upvotes: 2

user529758
user529758

Reputation:

This is absolutely wrong what you're doing. Casting a value's type doesn't "convert" the values but just tells the compiler to treat it as a different type. As an int and your struct most probably have different sizes, so do the arrays created from them, so you even write/read past the bounds of your integer array. If you really want to convert the integers to complex numbers, you have to code it yourself:

int number_of_items = 10; // e. g. there are 10 integers
int *int_arr = // however you obtain the integer array
complex_float *cpx_arr = malloc(sizeof(*cpx_arr) * number_of_items);
int i;
for (i = 0; i < number_of_items; i++)
{
    cpx_arr[i].re = (float)(int_arr[i]);
    cpx_arr[i].im = 0.0f;
}

Of course, don't forget to free(cpx_arr) after use.

Upvotes: 4

sardok
sardok

Reputation: 1116

structures can get different size than it looks like when compiled for optimization reasons. Please look at http://en.wikipedia.org/wiki/Data_structure_alignment for more information. However you can disable it by using gcc's extension packed (http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html). Beside that, you're having a potential unaligned access problem. It's ok for x86 which is handled by an architecture but for sake of portable code, instead of type casting, i would use memcpy.

Upvotes: 1

Related Questions