6

I had this question in a test, and I still don't understand the answer I was given:

Let's say I wrote the following code:

#include <math.h>
#include <stdio.h>

float cos(float x){
    return 1-x*x/4;
}

int main()
{
    printf("%0f",cos(0.05f)+sin(0.05f));
}

Let's assume cos and sin are declared and defined in the math library (receiving and returning double), and I'm trying to link my code with the math library.

Another assumption is that cos is defined in math.c.

The question was:

"Will the code compile/link successfully? if so, which cos function will be called?"

The answer was:

"Yes, the code will compile and my cos will be called".

How could this behavior be explained? Aren't these multiple definitions of the same function?

Peter Bratton
  • 6,302
  • 6
  • 39
  • 61
Paz
  • 737
  • 7
  • 22
  • How did you arrive at your answer `""Yes, the code will compile and my cos will be called""`? – Brandin Jan 22 '14 at 14:37
  • @Brandin that was the teacher's solution. – Paz Jan 22 '14 at 14:38
  • Compiling with GCC-4.8.1 I get an error: "conflicting types for 'cos'" – Kninnug Jan 22 '14 at 14:40
  • @Paz I think it is implementation depenedent. It means your teacher's solution is not correct. If you actually want to redefine cos you should name it something else like `my_cos`. Then for convenience you could `#define cos(X) my_cos((X))` in the source files where you want to use your custom version – Brandin Jan 22 '14 at 14:41
  • 2
    @Brandin: it is not implementation dependent, cos is a standard function and overloading is not allowed in C. –  Jan 22 '14 at 14:51
  • 6
    Your teacher may have made a mistake and intended to use `double cos(double x)`. In this case, many C implementations will accept the program, and it will link and run because the linker takes **every** module from the object modules it is supplied but only takes the **needed** modules from the libraries it is supplied. Thus, because `cos` is already defined in the program, the linker will not take it from the math library. However, although this works in many C implementations, it violates the rules of standard C, which reserves the library identifiers; normal programs may not define them. – Eric Postpischil Jan 22 '14 at 14:59
  • 1
    @EricPostpischil: I'd make your comment an answer. I think you've hit the nail on the head. – Paul S Jan 22 '14 at 15:01
  • Ouch, again one of these course questions about C where obviously the teacher doesn't fully understand C himself. – Jens Gustedt Jan 22 '14 at 15:32
  • @paz would you please check my answer? As I found a topic here similar to the case you want exactly, you can override the math.h library... – Ahmed Hamdy Jan 24 '14 at 13:29
  • @AhmedHamdy thanks for the attempt, but I asked my teacher and he explained his intention: using math as a statically linked library, and in that case our "local" version of 'cos' will be chosen. – Paz Jan 24 '14 at 15:51

6 Answers6

7

Your teacher may have made a mistake and intended to use double cos(double x). In this case, many C implementations will accept the program, and it will link and run because the linker takes every module from the object modules it is supplied but only takes the needed modules from the libraries it is supplied. Thus, because cos is already defined in the program, the linker will not take it from the math library. However, although this works in many C implementations, it violates the rules of standard C, which reserves the library identifiers; normal programs may not define them.

Another possibility is that your teacher did not intend to include math.h. This would make the declaration of cos not be an error, since it would not be conflicting with another declaration, but it would mean that sin should also be declared by the program, since it is used.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • The question states that in our (hypothetical) case cos is defined in math.c, and not math.h. Does that change things much? – Paz Jan 22 '14 at 15:07
  • 2
    @Paz: It depends on how the program is linked. If math.c is compiled to math.o and linked, I expect the linker to complain about multiple definitions of `cos`. If math.o is put into a library, such as libm.a, and then linked, I would expect the linker to take just the first definition and not complain. In a situation like this, I would consider that replacing the teacher might be the best option. – Eric Postpischil Jan 22 '14 at 15:09
  • Your latter suggestion must be what they meant. – Paz Jan 23 '14 at 09:34
2

It will not work at all.

You will see an error like this one:

conflicting types for 'cos'

I got it with codeblocks with gcc compiler ...

There is another solution you can use, please check this post: Override a function call in C

Community
  • 1
  • 1
Ahmed Hamdy
  • 2,547
  • 1
  • 17
  • 23
  • If `cos` is a macro definition, and you called `#undef cos` before redefining `cos` it would be okay. I'm pretty sure `cos` isn't a macro though. – Fiddling Bits Jan 22 '14 at 14:43
  • 1
    @FiddlingBits that isn't mentioned in the question, so I'm assuming that isn't the case. – Paz Jan 22 '14 at 14:45
  • I'm pretty sure that your error output does not come from codeblocks but the compiler called by codeblocks. – urzeit Jan 22 '14 at 14:51
2

It will not compile.

I added a return 0; at the end of main() to remove a second problem with -Wall -Werror. If you do this you will see:

$ gcc -Wall -Werror costest1.c -o costest -lm
costest1.c:5:1: error: conflicting types for ‘cos’

This fails at the compile stage because math.h also defines a function called cos. Note the prototype for cos is:

double cos(double x);

not

float cos(float x);

If you did not include math.h, you would be able to compile, but would get:

$ gcc -Wall -Werror costest1.c -o costest -lm
costest1.c:5:1: error: conflicting types for built-in function ‘cos’ [-Werror]
costest1.c: In function ‘main’:
costest1.c:13:3: error: implicit declaration of function ‘sin’ [-Werror=implicit-function-declaration]
costest1.c:13:32: error: incompatible implicit declaration of built-in function ‘sin’ [-Werror]
cc1: all warnings being treated as errors

This is because cos is not a normal function, but handled as a builtin. As you can see it's defined in terms of sin. If cos were a normal function, you would see a duplicate symbol error of some sort.

In C you cannot have two functions with the same name even if they have different arguments. In C++ you can, in that identically named methods may differ by the calling parameters (but not just by the return type).

abligh
  • 24,573
  • 4
  • 47
  • 84
  • 1
    Using `-Werror` is not a valid test of whether a program conforms to standard C, as it alters the behavior of the compiler to reject some conforming programs. – Eric Postpischil Jan 22 '14 at 14:53
  • Fair enough. Without `-Werror` it compiles, but I believe this is because `cos` is defined in `math.h` in terms of `sin`, so there is no actual function `cos` in the library. – abligh Jan 22 '14 at 14:59
  • In particular not having a `return` statement in `main` is completely valid. `main` is special in that regard. – Jens Gustedt Jan 22 '14 at 15:29
  • I thought you were meant to declare `main()` as `void` if you did not want to return a value. – abligh Jan 22 '14 at 15:34
  • @abligh The `main()` function must always be defined to have a return value of type `int`. – This isn't my real name Jan 23 '14 at 02:32
2

EDIT:

I assume the question was about C++ and not C since compiling your code as a C program will generate conflicting types error: https://eval.in/93380.

This behaviour is caused by the Function Overloading. The cos() function has the assembly name _cos@double and redeclaring the cos() function to be accepting a float argument will have the assembly name_cos@floatand it will not conflict with the cos() defined in the math library. And calling cos() with a float argument will be translated to a call to the assembly function _cos@float which is your own cos().

Note that Function Overloading is allowed only in C++ and not C.

In C you can only do it without changing the arguments and the return types of the function (https://eval.in/93381) otherwise the previous error will be generated.

As the assumption clarifies (cos is defined in math.c), the cos() function in the case is other than the one defined in the math.h in which case the the answer would be true if it was defined to be accepting an argument of type float and returning a value of type float. In this case the program will compile without any issues.

rullof
  • 7,124
  • 6
  • 27
  • 36
  • unfortunately it is indeed C and not C++. – Paz Jan 22 '14 at 14:59
  • 1
    @Paz This can't be true in C as you're redefining `cos` with different arguments types. This will always generate conflicting types error https://eval.in/93368 – rullof Jan 22 '14 at 15:02
  • it was explicitly mentioned in the test that the math.h\math.c version of cos() is defined with 'double'. So this double definition will inevitably cause an error? – Paz Jan 22 '14 at 15:30
  • @Paz If this is the case your teacher may have made a mistake. – rullof Jan 22 '14 at 15:31
  • 1
    @Paz: yes, it's a constraint violation (see my answer below). If your teacher is successfully compiling that code and running it as described, then he or she is either using a C++ compiler or a seriously non-conforming C compiler. – John Bode Jan 22 '14 at 16:19
  • @JohnBode Which is clearly described and answers has votes up to +5 and non of them was accepted! – rullof Jan 22 '14 at 16:22
2

Online C2011 standard:

6.7 Declarations
...
Constraints
...
4 All declarations in the same scope that refer to the same object or function shall specify compatible types

The code you posted violates the above constraint; math.h declares cos as

double cos(double x);    

This behavior cannot be explained as C; it can be explained as C++, which allows for name overloading.

Make sure you're really talking about C and not C++, otherwise you are going to wind up being very confused.

John Bode
  • 119,563
  • 19
  • 122
  • 198
0

No it does not compile.

The header file math.h declares double cos(double). Attempting to overload is not allowed in C.

error C2371: 'cos' : redefinition; different basic types
  • At least in your environment. See @Eric's answer above. – ryyker Jan 22 '14 at 15:13
  • In any environment. This MUST raise a compilation error. Function signatures must be declared uniquely in C. Eric does not contradict this. –  Jan 22 '14 at 18:34