user14450516
user14450516

Reputation: 11

Strange result with pointer casting

I was testing if it was possible to have int and float values in the same array, and I wrote this code:

#include <stdio.h>
#include <stdlib.h>

int main()

{
    int v[4]={0,0,0,0};
    *((float*)(&v[1]))=45.6;
    printf("%f\n",*((float*)(&v[1])));

    printf("%f\n",v[1]);
    return 0;



}

I was expecting to have 45.599998 and 0 or have the same values on both printf but i get different results: 45.599998 45.599983 Why?, What is happening?

EDIT
By the way, I want to emphasize that for this question I'm not as interested in alternatives to do this, I'm more interested in understanding why is not working.

Upvotes: 0

Views: 73

Answers (3)

ryyker
ryyker

Reputation: 23208

In the example code, as pointed out in the comments, undefined behavior is invoked. (In this case I believe strict aliasing is being violated.)

"[is it] possible to have int and float values in the same array"

Not in C, an array of any type can contain only one type. However, if a variation of this arrangement will work for you, both types can be defined in a single instance of a compound type, such as an array of struct. Eg:

typedef struct {
   int iVal;
   float fVal;
} val_s;

val_s val[10];

Now you have an array of 10 elements of type val_s, for which each element includes both int and float type members.

Another variation of compound type in C (which has been pointed out to me in comments that may be more of what you are looking for) is a built-in C type that allows multiple types to share the same memory, is a union. The caveat is that it is up to the programmer to keep track of which of the members was last written to, as only one member can contain a value at any given time...

Example:

typedef union {
   int iVal;
   float fVal;
} val_s;

val_s val;

Upvotes: 2

John Bollinger
John Bollinger

Reputation: 180058

I was expecting to have 45.599998 and 0 or have the same values on both printf but i get different results: 45.599998 45.599983 Why?, What is happening?

Suppose we eliminate some of the undefined behavior in your code by using this variation:

#include <string.h>
#include <stdio.h>

int main() {
    int v[4]={0,0,0,0};
    float f = 45.6;
    memcpy(&v[1], &f, sizeof f);

    printf("%f\n", f);
    printf("%f\n", v[1]);

    return 0;
}

This still has undefined behavior because format directive %f is not properly type-matched with v[1], but otherwise it is ok as long as float is not larger than int, and int has no trap representations (both of which hold for most C implementations).

Even in the likely event that the values of f and v[1] have identical byte-sequence representations, the difference between their types has an important consequence with respect to this code. The variable arguments of a variadic function such as printf are subject to the "default argument promotions". These leave values of type int unchanged, but they promote floats to type double. Thus, if your float and double differ in practice, which they typically do, then

  1. printf receives different argument values in the two cases, even when only the byte sequence of each argument is considered, and
  2. in the v[1] case, printf probably does not receive a wide enough value.

So if you want to indulge in the dubious practice of hypothesizing about what the program actually does in this case of undefined behavior, then one of the more likely possibilities is that in the v[1] case it looks at the byte sequence of a float, combined with some additional random bytes that happen to be laying around in memory, interprets them as if they were the bytes of a double, and, by stroke of luck and the details of the chosen test value, it comes up with a numeric value close to, but not exactly matching the double to which your float was promoted.

Upvotes: 1

Govind Parmar
Govind Parmar

Reputation: 21532

Using a floating point specifier and passing an integral value to satisfy that argument in the format string is undefined behavior, which is to say, all bets are off.

Lots of systems pass integral arguments and floating point arguments in completely different ways; some don't. 'Why' cannot be answered fully. You happen to be on a system whose calling convention doesn't seem to pass integral and floating point arguments differently.

Upvotes: 0

Related Questions