-2

I have a simple C program with two files: main.c and test.c.

main.c

#include <stdio.h>
int main(){
    printf ("%f\n", test());
    return 0;
}

test.c

double test(){
    return 2.5;
} 

I then compile the code with the command gcc main.c test.c. When I run it, the program outputs 0.000000. Not 2.500000 as I expected. I don't know why.

I don't have this problem when I define test() and main() in the same file. I also don't have this problem if I declare double test(); just above the main function in main.c. But with that said I'm also able to declare float test(); in main.c, in which case the compiler gives me no warnings even though the declaration does not match the definition, and the program incorrectly outputs 0.000000 as before.

I think what I don't understand is how the linking process works and what are the real scoping rules of variables and functions defined in other files.

HazySmoke
  • 263
  • 1
  • 8
  • 2
    Turn on compiler warnings. That should tell you what's wrong. – yellowantphil May 19 '17 at 17:39
  • 1
    Possible duplicate of [Compiling multiple C files with gcc](http://stackoverflow.com/questions/18777326/compiling-multiple-c-files-with-gcc) – Iłya Bursov May 19 '17 at 17:41
  • 1
    If you declare `float test();` in main.c, you are *explicitly **lying to your compiler***. You get what you deserve. – EOF May 19 '17 at 17:41
  • @EOF It's possible that a "lying" declaration is done accidentally. Why then doesn't the compiler make any attempt to provide a warning for the problem? – HazySmoke May 19 '17 at 17:45
  • 1
    This is why C99 and C11 require you to declare functions before you use them — the assumptions that the compiler has to make are wrong. In `main.c`, the function `test()` is assumed to return an `int` because you didn't declare it and didn't enable enough compiler options and warnings to ensure that such badly formed C was rejected. – Jonathan Leffler May 19 '17 at 17:45
  • @HazySmoke The traditional way is to `#include` a header for the function declarations. If the identical header is included both in main.c and test.c, this problem can't occur without the compiler seeing it. – EOF May 19 '17 at 17:46
  • The compiler didn't warn you because you didn't ask for warnings! – yellowantphil May 19 '17 at 17:47
  • As to why no warning: the compilers compile code and trust that you know what you're doing, unless you ask them to help you. If you're using GCC, consider using `gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition …` — I don't risk using code I write that doesn't compile cleanly like that except in extraordinary circumstances. – Jonathan Leffler May 19 '17 at 17:48
  • @yellowantphil Even with -Wall the compiler doesn't warn me of the conflicting declaration. – HazySmoke May 19 '17 at 17:52
  • @HazySmoke: The compiler will warn you about a missing declaration/prototype! In case it does not: compile as standard C (i.e. C11), at least C99. C90 is outdated since 18 years, K&R-C should R.I.P. since 28 years! Don't ignore compiler warnings. All this will be explained in every good C book. Don't learn C by trial&error or youtube! – too honest for this site May 19 '17 at 17:56
  • I just tried it, and `gcc main.c test.c -Wall` gives me a couple warnings. – yellowantphil May 19 '17 at 18:01
  • In case you saw the warnings but didn't know what they meant, "implicit declaration of function 'test'" means that the compiler assumed that `test()` returned an `int`. That's a holdover from long ago (K&R C, maybe) and is not a useful feature these days, so you never want your compiler to assume function definitions. – yellowantphil May 19 '17 at 18:04
  • @yellowwantphil When I don't declare the function at all, then yes I do get the warning as you said. But when I declare the function with the return type being float, I get no warnings. Hence I said "the compiler doesn't warn me of the *conflicting* declaration". – HazySmoke May 19 '17 at 18:06
  • Oh, in that case, put the function prototype in a header file, and include that header in both of your C files. The compiler should complain when it tries to compile test.c. – yellowantphil May 19 '17 at 18:08
  • btw not related but I don't understand why my question has downvotes. (I'm only talking to the downvoters, if you are respectful then everything's cool.) I don't think I violated any community guidelines. The suggested duplicate question is different because that one doesn't talk about calling external functions/linking. If the answer is so obvious to you then why not just explain how the linking process works and correct my mental model of it? Someone tell me if asking questions that other community members find obvious is somehow against the rules. – HazySmoke May 19 '17 at 18:11
  • 1
    I didn't downvote, but I'm guessing it's because the solution is obvious to more experienced C programmers. That sometimes indicates a lack of research. Some people here expect a lot of research (reading tutorials, internet search, whatever) before questions are posted. – yellowantphil May 19 '17 at 18:15

1 Answers1

0

You need to tell main what test() returns. Also "%lf" is for doubles.

#include <stdio.h>

double test();

int main(){
    printf ("%lf\n", test());
    return 0;
}

Otherwise, the compiler will incorrectly assume it returns int (and will interpret the bit pattern of the return value as an int). If you specify float (again, incorrectly), then the compiler will attempt to interpret the bit pattern of the returned double as a float.

L. Scott Johnson
  • 4,213
  • 2
  • 17
  • 28