I'm a beginner with C and I can't find the solution for this "error" ...
(I don't want to just print what I read with scanf, that's just an extract from a bigger program, so can you try not to create a new code but to modify this ?)
Here's the code
#include <stdio.h>
float function(x){
return x;
}
int main(){
float x;
scanf("%f", &x);
printf("%f \n", function(x));
return 0;
}
And if you don't mind ... can you explain the reason why it doesn't work in this way ? Thank you a lot
You defined your function as:
float function(x){
return x;
}
If you want the function to take a float argument, you need to say so:
float function(float x){
return x;
}
Fixing that should fix your problem. You don't really need to worry about why your incorrect program behaves the way it does.
But if you're curious ...
Prior to the C99 standard, C had an "implicit int" rule. In this case, the parameter x would be of type int because you didn't specify its type explicitly. But since you used an old-style definition, not a prototype, you haven't told the compiler that the argument should be of type int. (Yes, old-style function declarations and definitions can cause some serious problems. That's why we have prototypes.)
So when you call your function with a float argument, the compiler doesn't complain, and it doesn't convert your argument from float to int. Instead, it promotes your argument from float to double (that's just one of the rules for calling a function with no visible prototype, or for calling a variadic function like printf), and the function itself assumes that you really passed it an int.
Result: The behavior is undefined.
One likely result is that the function will treat the double argument as if it were of type int, yielding garbage. Another is that it will read the int value from some other memory location or register, yielding even worse garbage.
Always enable warnings. Always pay attention to any warnings your compiler produces. Always ask your compiler to conform to the C99 or C11 standard unless you have a specific reason not to. And always declare and define your functions with prototypes. (A prototype is a function declaration that specifies the types of the parameters.)
This also means that int main() should be int main(void). That's not likely to matter (unless you call main recursively, which would be silly), but it's a good habit.
You never defined the type of the function's parameter x. Without an explicit type, the type defaults to int. As a result, the float that you pass to the function gets converted to an int and gets truncated.
Add the parameter type to the function definition.
float function(float x){
return x;
}
Related
I have a simple code, where my functions are declared before main function like that:
int function1();
int function2();
int main() {
/* ... */
function1(x,y);
function2(x,y);
/* .... */
}
int function1(int x, float y) { /* ... */ }
int function2(int x, float y) { /* ... */ }
And after my main function I have definitions of functions:
Is there some difference, when I declare functions before main like this?
int function1(int x, float y);
int function2(int x, float y);
int main() {
/* ... */
function1(x,y);
function2(x,y);
/* .... */
}
int function1(int x, float y) { /* ... */ }
int function2(int x, float y) { /* ... */ }
Yes, they are different.
In the first example, you are just telling the compiler about the name and return type of the function and nothing of its expected arguments.
In the second example you are telling the compiler the full signature of the functions, both return type and expected arguments, prior to calling them.
The second form is pretty much universally better as it helps you compiler do a better job warning you when you have the wrong type or number of arguments when calling the function.
Also note int function() in C is a function that can accept any arguments, not a function that accepts no arguments. For that you need an explicit void, i.e int function(void). This mostly trips up those coming to C from C++.
See also:
Why does a function with no parameters (compared to the actual function definition) compile?
To demonstrate why the first, antiquated form is bad in modern C, the following program compiles without warning with gcc -Wall -ansi -pedantic or gcc -Wall -std=c11.
#include<stdio.h>
int foo();
int main(int argc, char**argv)
{
printf("%d\n", foo(100));
printf("%d\n", foo(100,"bar"));
printf("%d\n", foo(100,'a', NULL));
return 0;
}
int foo(int x, int y)
{
return 10;
}
UPDATE: M&M brought to my attention that my example uses int not float for the functions. I think we can all agree that declaring int function1() is bad form, but my statement that this declaration accepts any arguments is not quite correct. See Vlad's answer for relevant spec section explaining why that is the case.
The difference is that then there is a function prototype as in the second code snippet then the compiler checks that the number and types of arguments correspond to the number and types of the parameters. The compiler can issue an error at the compilation-time if it will find an inconsistence.
If there is no function prototype as in the first code snippet then the compiler performs default argument promotions on each argument that includes the integer promotions and conversion of expressions of type float to type double. If after these operations the number and types of promoted arguments do not correspond to the number and types of parameters the behaviour is undefined. The compiler can be unable to issue an error because the function definition can be in some other compilation unit.
here are relevant quotes from the C Standard (6.5.2.2 Function calls)
2 If the expression that denotes the called function has a type that
includes a prototype, the number of arguments shall agree with the
number of parameters. Each argument shall have a type such that its
value may be assigned to an object with the unqualified version of the
type of its corresponding parameter.
6 If the expression that denotes the called function has a type that
does not include a prototype, the integer promotions are performed on
each argument, and arguments that have type float are promoted to
double. These are called the default argument promotions. If the
number of arguments does not equal the number of parameters, the
behavior is undefined. If the function is defined with a type that
includes a prototype, and either the prototype ends with an ellipsis
(, ...) or the types of the arguments after promotion are not
compatible with the types of the parameters, the behavior is
undefined. If the function is defined with a type that does not
include a prototype, and the types of the arguments after promotion
are not compatible with those of the parameters after promotion, the
behavior is undefined, except for the following cases:
— one promoted type is a signed integer type, the other promoted type
is the corresponding unsigned integer type, and the value is
representable in both types;
— both types are pointers to qualified or unqualified versions of a
character type or void.
As for your code snippets then if the second parameter had type double then the code would be well-formed. However as the second parameter has type float but the corresponding argument will be promoted to type double then the first code snippet has undefined behaviour.
Yes, they're different; the second is correct, the first one as a whole is wrong. It is so wrong that GCC 5.2.1 refuses to compile it altogether. That it works for you at all is just a fluke:
/* this coupled with */
int function1();
int main() {
/* this */
function1(x, y);
}
/* and this one leads to undefined behaviour */
int function1(int x, float y) {
/* ... */
}
In the code above, the declaration int function1(); does not specify the argument types (it does not have a prototype), which is considered an obsolescent feature in C11 (and C89, C99 for that matter) standard. If that kind of function is called, default argument promotions are done on the arguments: int is passed as is, but float is promoted to double.
As your actual function expects arguments of (int, float), not (int, double), this will result in undefined behaviour. Even if your function expected a (int, double) but y was an integer, or say you called it with function1(0, 0); instead of function(0, 0.0);, your program would still have undefined behaviour. Fortunately GCC 5.2.1 notices that the declaration and definition of function1 are conflicting:
% gcc test.c
test.c:9:5: error: conflicting types for ‘function1’
int function1(int x, float y) {
^
test.c:9:1: note: an argument type that has a default promotion can’t
match an empty parameter name list declaration
int function1(int x, float y) {
^
test.c:1:5: note: previous declaration of ‘function1’ was here
int function1();
^
test.c:12:5: error: conflicting types for ‘function2’
int function2(int x, float y) {
^
test.c:12:1: note: an argument type that has a default promotion can’t
match an empty parameter name list declaration
int function2(int x, float y) {
^
test.c:2:5: note: previous declaration of ‘function2’ was here
int function2();
^
and the compiler exits with error code, whereas my tcc compiles it happily, no diagnostics, nothing. It just produces broken code. The same is true of course, if you had the declaration in a header file, and the definition in a different compilation unit that did not include that declaration.
Now, should the compiler not detect this case, at runtime, anything could happen, as expected for undefined behaviour.
For example, suppose a case that the arguments were passed on stack; on 32-bit processors int and float could fit in 4 bytes, whereas double could be 8 bytes; the function call would then push x as int and y as double even if it was float - in total the caller would have pushed 12 bytes and the callee would only expect 8.
In another case, suppose you'd call the function with 2 integers. The calling code would then load these into integer registers, but the caller would expect a double in a floating point register. The floating point register could contain a trap value, which, when accessed would kill your program.
What is worst, your program might now behave as expected, thus containing a heisenbug that could cause problems when you recompile the code with a newer version of compiler, or port it to another platform.
In the first case, main() performs integer promotions on each argument and float-to-double promotions. These are called "default argument promotions". So you'll probably end up calling the functions incorrectly, by passing an int and a double wheras the functions expect an int and a float.
See Default argument promotions in C function calls and the answers for more details.
The Problem
I'm writing the following code, which, as excerpted below, should return the total amount of money depending on the number of each type of coin.
static int qNum = 0;
static int dNum = 0;
static int nNum = 0;
static int pNum = 0;
int main(){
float totalCost;
totalCost = totalMoneyCalc();
}
float totalMoneyCalc(void){
float total;
total = qNum*.25 + dNum*.10 + nNum*.05 + pNum*.01;
return total;
}
The Errors I'm Getting
note: previous implicit declaration of ‘totalMoneyCalc’ was here
totalCost = totalMoneyCalc();
error: conflicting types for ‘totalMoneyCalc’
float totalMoneyCalc(){
However, when I remove the "float" part of the totalMoneyCalc() function, it doesn't return any more errors. Aren't you supposed to assign functions types?
What I've Tried
I looked at this question on SO, which says something about having to pass in void as a param for functions that don't take in anything but adding that to the original code didn't work either.
I also checked out some primers on using floats for functions in C, but I followed those and it's still not working.
Am I supposed to be doing something with pointers? I don't understand why returning a value in a function to be assigned to a variable is different from ints to floats. If anyone has suggestions, fixes, or explanations, I'd really appreciate it.
Yes, all C functions have types. Prior to the 1999 standard, it was legal to omit the return type from a declaration; that would implicitly give it a return type of int. As of C99, the return type must always be specified explicitly.
Also prior to C99, it was legal to call a function with no visible declaration. The compiler would assume a function with a return type of int (that's the "previous implicit declaration" referred to in the error message). C99 dropped that rule; now all functions must be visibly declared before you can call them.
Assuming you're using gcc (that looks like a gcc error message), the compiler enforces the C90 rules by default. The problem it's reporting is that the implicit declaration of totalMoneyCalc (as a function returning int) conflicts with the later explicit declaration as a function returning float.
The solution is to declare totalMoneyCalc before the call. You can either add a separate "forward" declaration before main:
float totalMoneyCalc(void);
or you can move the entire definition above main. (This is a good idea even in C90.)
A minor point: int main() should be int main(void).
The compiler needs to know about the function before you use it. If the function is unknown to the compiler then it will not be able to know whether the function returns double or float or if it's first parameter is a pointer or a struct, so it will by default think of them all as int's.
You can to add a function prototype before main()
float totalMoneyCalc(void);
or move the entire function definition before main().
How does the following code work even though the signature of the function in the declaration doesn't match with the definition? The function declaration has empty parameter list, yet the definition has one parameter. Why the compiler doesn't give error?
#include <stdio.h>
double f(); //function declaration
int main(void)
{
printf("%f\n", f(100.0));
}
double f(double param) //function definition
{
return 5 * param ;
}
It compiles and runs fine (ideone).
But if I change the type of the parameter in the definition, from double to float, it gives the following error (ideone):
prog.c:7: error: conflicting types for ‘f’
prog.c:8: note: an argument type that has a default promotion can’t match an empty parameter name list declaration
prog.c:2: error: previous declaration of ‘f’ was here
What is wrong with float? Why does it give error with float but not with double?
Here is the list of pairs of declaration and definition, along with which pair works, and which not:
Works (ideone)
double f(); //declaration
double f(double param); //definition
Does not work (ideone)
double f(); //declaration
double f(float param); //definition
Works (ideone)
float f(); //declaration
float f(double param); //definition
Does not work (ideone)
float f(); //declaration
float f(float param); //definition
So as it seems, whenever the parameter-type is float, it doesn't work!
So I've basically two questions:
Why does the first example work even though there is a mismatch in the declaration and the definition?
Why does it not work when the parameter-type is float?
I tried understanding the section §6.5.2.2 (C99), but the language is so cryptic that I couldn't clearly understand. I don't even know if I read the correct section. So please explain these behaviors in simple words.
Your assumption that declaration does not match the definition is incorrect. (That would be the case in C++, but not in C). In C language the
double f();
declaration does not fully declare the function, i.e. it does not introduce the prototype. It only announces the fact that function f exists and that its return type is double. It says absolutely nothing about the number and the types of fs arguments. The arguments can be absolutely anything. In that sense the declaration in your example does match the definition (i.e. it doesn't contradict the definition, which is good enought for C compiler).
If you really wanted the declare a function that takes no arguments, you'd have to specify an explicit void in the parameter list
double f(void);
That would indeed contradict the definition. What you have originally does not.
When you call a function that has been declared with empty parameter list (), it is your responsibility to supply the proper number of arguments of proper type. If you make a mistake, the behavior is undefined. This is what the compiler warns you about when you change the actual parameter type to float.
Your analysis of "pairs" of declaration and definition is not entirely correct. It is misguided. It is not really about the declaration and definition. It is really about the definition and the way you call your function. In the original case you call it with a double argument and the function is declared with a double parameter. So everything is matching. But when you call it with a double argument and declare it with a float parameter, you get a mismatch.
Also note, that when a function is declared without a prototype, float arguments are always promoted to double arguments. For this reason, it is not possible to pass a float argument to a function declared with () parameter list. If you want to have float arguments, always use prototypes (the same applies to char and short arguments as well).
C allows the function declaration to be empty. From C99 6.7.5.3/14:
The empty list in a
function declarator that is not part
of a definition of that function
specifies that no information about
the number or types of the parameters
is supplied.
This is distinct from a void parameter list, which is explicitly stating that the function has no arguments. From 6.7.5.3/10:
The special case of an unnamed
parameter of type void as the only
item in the list specifies that the
function has no parameters.
Note also that if the types aren't declared, then your declaration is not a prototype. From 6.2.1/2:
A function prototype is a declaration
of a function that declares the types
of its parameters.
The second question is indeed related to C99 6.5.2.2/6:
If the expression that denotes the
called function has a type that does
not include a prototype, the integer
promotions are performed on each
argument, and arguments that have type
float are promoted to double.
So in your case, float gets promoted to double whenever the function is called, and a double is put on the call stack (or in eax or whatever). But of course, if your function definition takes a float, it would read a float off the call stack, which would lead to a binary incompatibility. The compiler knows this, hence the error message.
In C, an empty parameter list in the declaration means the function can be called with 0 or more arguments.
Such functions, when called with a floating-point number, implicitly take it as a double. (And integral parameters as int.)
So when you call foo(100.0), you are calling it with a double. If you try to call it with a float, the argument will be converted to double at the time of the call.
This will not work if you define the function to take a float, because the way doubles and floats are passed is different. Hence the compiler is helpfully giving you an error.
Be glad you made this mistake in 2011 and not 1985, because compilers used to be pretty stupid and this was a nightmarish kind of bug to track down.
Bottom line: It is very bad style to declare functions with empty parameter lists in modern C. Declare the function properly, and if it to be referenced by multiple translation units, put the declaration in a header file.
[edit]
As detly points out in a comment, if you actually want to declare a function to take zero arguments, declare it to take void. (Or switch to C++...)
In C, an empty function declaration is like using ... in C++. That is it matches any number and type of arguments. The problem with using a float instead of a double is that float automatically promotes to double. When calling f(...) (to borrow C++ notation), it doesn't know what type is expected, so it gets promoted to double. Later, when you redeclare f to take a float argument, that conflicts with the implicit declaration of f as f(double).
I thought the difference is that declaration doesn't have parameter types...
Why does this work:
int fuc();
int fuc(int i) {
printf("%d", i);
return 0;
}
but this fails compiling:
int fuc();
int fuc(float f) {
printf("%f", f);
return 0;
}
with the message:
error: conflicting types for ‘fuc’. note: an argument type that has a default promotion can’t match an empty parameter name list declaration
A declaration:
int f();
...tells the compiler that some identifier (f, in this case) names a function, and tells it the return type of the function -- but does not specify the number or type(s) of parameter(s) that function is intended to receive.
A prototype:
int f(int, char);
...is otherwise similar, but also specifies the number/type of parameter(s) the function is intended to receive. If it takes no parameter, you use something like int f(void) to specify that (since leaving the parentheses empty is a declaration). A new-style function definition:
int f(int a, char b) {
// do stuff here...
}
...also acts as a prototype.
Without a prototype in scope, the compiler applies default promotions to arguments before calling the function. This means that any char or short is promoted to int, and any float is promoted to double. Therefore, if you declare (rather than prototype) a function, you do not want to specify any char, short or float parameter -- calling such a thing would/will give undefined behavior. With default flags, the compiler may well reject the code, since there's basically no way to use it correctly. You might be able to find some set of compiler flags that would get it to accept the code but it would be pretty pointless, since you can't use it anyway...
prototype = forward declaration, so you can use it before you tell the compiler what it does. It still has parameters, however.
Useful in a lot of respects!
The declaration int fuc(float); tells the compiler that there exists a function fuc which takes a float and returns an int.
The definition int fuc(float f) { /*...*/ } tells the compiler what fuc actually is and also provides the declaration as well.
The difference between a declaration and definition is the difference between saying that a size 6 blue hat exists and and handing someone a size 6 blue hat: the declaration says that there is such a thing, the definition says that this thing right here is the thing in question.
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?
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.
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.
The compiler is complaining that it assumed function_call is an int returning function as indicated by the standard, and then you tell it is a void function. The compiler won't care about arguments unless you are explicitely declaring them to be different to the actual function. You can pass it no arguments and it won't complain.
You must always declare your functions because this error will go undetected if the function is in other modules. If the function should return any type that could be larger than int such as void* or long, the cast to int in the caller function will most likely truncate it, leaving you with a weird bug.
Everyone has missed one thing. In ISO C an ISO-syntax prototype overrides default argument promotion.
And in that case the compiler is allowed to generate different code (!) based purely on the style of definition. This gets you K&R compatibility, but you can't always call between the language levels unless you have written the ISO code as K&R expects or modified the K&R code to see the ISO prototypes.
Try it with cc -S -O ...
extern float q; void f(float a) { q = a; }
movl 8(%ebp), %eax
movl %eax, q
extern float q; void f(a) float a; { q = a; } // Not the same thing!
fldl 8(%ebp)
fstps q