Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C: type conversion when passing an argument on a function call

From The C Programming Language 2nd Edition:

Since an argument of a function call is an expression, type conversions also take place when arguments are passed to function. In absence of a function prototype, char and short become int, and float becomes double.

By reading the text, I am getting an impression that unless you explicitly specify the argument type by either using cast or function prototype, function arguments will always be passed as either passed as int or double.

In order to verify my assumption, I compiled the following code:

#include <stdio.h>

main()
{
     unsigned char c = 'Z';
     float number = 3.14f;
     function_call(c, number);
}

void function_call(char c, float f)
{
}

After compilation I get the following warnings:

typeconversion.c:11: warning: conflicting types for ‘function_call’

typeconversion.c:7: warning: previous implicit declaration of ‘function_call’ was here

My guess is c and number were both converted to int and double on the function call, and were then converted back to char and float. Is this what actually happened?

like image 804
Midnight Blue Avatar asked Aug 21 '09 20:08

Midnight Blue


People also ask

How are arguments passed to a function in C?

Arguments in C and C++ language are copied to the program stack at run time, where they are read by the function. These arguments can either be values in their own right, or they can be pointers to areas of memory that contain the data being passed. Passing a pointer is also known as passing a value by reference.

How are arguments passed through function call?

Arguments are passed by value; that is, when a function is called, the parameter receives a copy of the argument's value, not its address. This rule applies to all scalar values, structures, and unions passed as arguments. Modifying a parameter does not modify the corresponding argument passed by the function call.

In what situation type conversion is necessary in C?

Generally takes place when in an expression more than one data type is present. In such condition type conversion (type promotion) takes place to avoid loss of data. All the data types of the variables are upgraded to the data type of the variable with largest data type.


2 Answers

Casts are irrelevant, it's the (possibly implicit) prototype that matters.

void foo(short s) {
    // do something
}

int main(void) {
  signed char c = 'a';

  foo(c);  // c is promoted to short by explicit prototype
  bar(c);  // c is promoted to int by implicit prototype
}

void bar(int i) {
    // do something
}

When the book says "an argument of a function call is an expression" it means that the same type promotion rules apply. It might be easier to understand if you think of a function argument as an implicit assignment to the variable specified in the function prototype. e.g. in the call to foo() above there's an implicit short s = c.

This is why casts don't matter. Consider the following code snippet:

signed char c = 'a';
int i = (short) c;

Here the value of c is promoted first to short (explicitly) then to int (implicitly). The value of i will always be an int.

As for char and short becoming int and float becoming double that refers to the default types for implicit function prototypes. When the compiler sees a call to a function before it has seen either a prototype or the definition of the function it generates a prototype automatically. It defaults to int for integer values and double for floating-point values.

If the eventual function declaration doesn't match to implicit prototype, you'll get warnings.

like image 194
Michael Carman Avatar answered Sep 21 '22 08:09

Michael Carman


You've got the general idea of what's wrong, but not exactly.

What happened is that when you wrote

function_call(c, number);

The compiler saw that you were calling a function that it had not seen yet, and so had to decide what its signature should be. Based on the promotion rule you quoted earlier, it promoted char to int and float to double and decided that the signature is

function_call(int, double)

Then when it sees

function_call(char c, float f)

it interprets this as a signature for a different function with the same name, which is not allowed in C. It's exactly the same error as if you prototype a function differently from how you actually define it, just that in this case the prototype is implicitly generated by the compiler.

So, it is this rule that's causing the issue, but the error doesn't have anything to do with actually converting values back and forth between types.

like image 42
Tyler McHenry Avatar answered Sep 21 '22 08:09

Tyler McHenry