tags:

views:

117

answers:

3

I ran the following code, and found some strange output.


int
mean_ansi (int num1, int num2)
{
  printf ("In %s\n", __FUNCTION__);
  printf ("num1,num2 is %d,%d\n", num1, num2);
  return (num1 + num2) / 2;
}

int
mean_K_and_R (num1, num2)
     int num1, num2;
{
  printf ("In %s\n", __FUNCTION__);
  printf ("num1,num2 is %d,%d\n", num1, num2);
  return (num1 + num2) / 2;
}


int
main ()
{
  int i = 6;
  double f = 1.0;

  printf ("In %s\n", __FUNCTION__);
  printf ("[f,i] = [%f,%d]\n", f, i);

  /* deliberate mistakes */
  mean_ansi (f, i);
  mean_K_and_R (f, i);

  return 0;
}

Output:

In main

[f,i] = [1.000000,6]

In mean_ansi

num1,num2 is 1,6

In mean_K_and_R

num1,num2 is 0,1072693248

Can anyone explain this behavior.

I saw the assembly but could not make out much.

Is there a difference in the way function arguments are pushed on the stack in both these syntaxes?

+1  A: 

I did some digging and found a thread indicating that K&R style function declarations don't create a prototype, so without a separate prototype the compiler is free to treat the arguments incorrectly if it desires.

I'm not sure how true this is, you could probably verify it by inserting a prototype quickly and seeing if the functions generate the same values.

In any case K&R style declarations are very outdated, as I'm sure you know, and should probably be avoided. If anything your problem is an example of that.

Dan Olson
+1  A: 

My guess is that in the first case, there wan an implicit conversion of double to int. In a second one, 64 bits representing 1.0 were interpreted as two integers. Number 1072693248 is represented binnary as

00111111111100000000000000000000

but if you take a look at this page, you'll see that this is actually an upper half of double representation of number 1. The first 0 is sign, 01111111111 is exponent and rest of zeros are an upper bits of fraction. Only thing I don't get is where the 1 for fraction went? Having said all this I would expect the output to be 1,1072693248.

Slartibartfast
the firt bit of the fractional part is always 1 (as long as the values are not subnormal), ie there's no need to store it
Christoph
+2  A: 

Dan Olson had the right idea, and Slartibartfast explained where the values com from:

The definition of mean_K_and_R() is treated as if it were defined like this

int mean_K_and_R();

ie the function takes any arguments and doesn't do any conversion aside from the default argument promotion.

If the cdecl calling convention is used, this means mean_K_and_R(f, i) will first push i to the stack, then the higher bits of f and then the lower bits of f.

But the function thinks it took two integer arguments, meaning num1 will now refer to the lower bits of f and num2 to the higher bits of f.

Christoph
This is probably aggravated by the fact that the arguments are used with printf, which does no type checking. What would happen when they're used in the expression return (num1 + num2) / 2? The function thinks they're ints, will it try to promote from double to int?
Dan Olson
@Dan: this has nothing to do with `printf()`: the compiler has already 'lost' the type information, ie there won't be any conversion done even in arithmetic expressions; the bit pattern of the double is interpreted as two integers because of it's particular position in the stack
Christoph
@Dan: if you know C++, think something along the lines of `reinterpret_cast<int [2]>(f)` where the resulting array holds `num1` and `num2`
Christoph