-4

I met this question in a interview occassion, the man asked me what is the result if i compile and execute the following code, and why. I am curious about this question and i did not really got it.

When i typing gcc f1.c f2.c and then ./a.out, it outputs a weird number:1717986918 in my x64 PC, and then i add a line in f2.c: extern double get_val(); it outputs 5.

f1.c:

double get_val()
{
    return 5.6;
}

f2.c:

#include<stdio.h>
//extern double get_val();
int main()
{
    int a=get_val();
    printf("%d\n", a);

    return 0;
}
Community
  • 1
  • 1
  • What answer did you expect? Also, prior to an "edit" the "extern" was uncommented... did that version give you the output you expected??? Lastly, with "extern" commented out, I get a warning message from "gcc", do you get one ??? – TonyB Sep 29 '16 at 22:53
  • Lot's of good resources on C, methods, functions and variable declarations on YouTube as well. Hang in there, and good luck with the job hunt! – BasicIsaac Sep 29 '16 at 23:00
  • @BasicIsaac: Avoid resources that refer to "methods"; C doesn't have them. (C++ member functions are sometimes called "methods", but that's not strictly correct either.) – Keith Thompson Sep 29 '16 at 23:02
  • @KeithThompson thanks for the heads up. I clicked on the C# tag and somehow ended up here. I don't see how this question how so many downvotes, it really is weird that the function would return a large number without the get_val() reference. – BasicIsaac Sep 29 '16 at 23:13
  • @BasicIsaac: Not that weird; see my answer. – Keith Thompson Sep 30 '16 at 01:50

3 Answers3

1

In f2.c, prior to the change, there is no declaration for get_val. So it assumes by default that the function returns an int. Because this does not match the actual return type of the function, this results in undefined behavior.

When you add a declaration, the correct return type of the function is known so the code works as expected.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • The assumption that an undeclared functions returns `int` applies only prior to the 1999 ISO C standard (C99), which dropped the "implicit `int`" rule. In C99 or later, a call an undeclared function is a constraint violation, requiring a compile-time diagnostic. Once the diagnostic is issued, if it's non-fatal, the subsequent behavior of the program is undefined, but the compiler can reject it altogether. – Keith Thompson Sep 29 '16 at 23:02
  • @KeithThompson nevertheless, common behaviour of compilers (even in C99 mode) is to issue a diagnostic and then proceed using the C89 behaviour – M.M Sep 29 '16 at 23:07
  • @M.M: Unfortunately true. – Keith Thompson Sep 29 '16 at 23:11
0

I tried to see how do you get the 1717986918 result and I can't figure out. In the two ways you decribe, I got a 5 printed. That's why:

  • You're "parsing" the double value of your function return whitin a int type (but

    int a = get_val();
    
  • After that, you are printing it on a format for a decimal

    printf("%d\n", a);
    
Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
0

You're calling the get_val() function with no visible declaration.

Don't do that. As of C99, the language forbids (see below) any call to a function without a visible declaration. (That declaration should be a prototype, which specifies the types of the parameters, but that's not required.)

Prior to C99 (which dropped the "implicit int" rule), a call to an undeclared function would require the compiler to assume that the function returns a result of type int, and that it expects the number and types of arguments that the call actually passes. If that assumption is violated by the actual function definition, as it is here since get_val() returns a double result, the behavior is undefined.

(By "forbids", I mean that such a call is a constraint violation. That means a conforming compiler must diagnose it, but is not required to reject it. Many compilers still permit calls to undeclared functions, often with a non-fatal warning, and implement the pre-C99 semantics. So a compiler might let you get away with it. Don't.)

So what happens is that get_val() is called, it returns a double result with the value 5.6 -- but the caller is expecting an int result, so it stores some undefined garbage value in a.

The value you're seeing, 1717986918, happens to be 0x66666666 in hexadecimal. In IEEE floating-point, at least on my system, the value 5.6 is represented as 0x6666666666661640. Apparently the value being stored happens to be the first half of the double value (most likely double is 8 bytes and int is 4 bytes).

So that explains the behavior you're seeing, but you should not count on it.

Never call a function without a visible declaration.

The usual way to get a visible declaration for a function defined in another source file is to #include the right header.

Here's an example of the right way to do it:

f1.h:

#ifndef F1_H
#define F1_H

extern double get_val(void);

#endif

f1.c:

#include "f1.h"

double get_val(void)
{
    return 5.6;
}

f2.c:

#include <stdio.h>
#include "f1.h"

int main(void) {
    int a = get_val();
    printf("%d\n", a);
    return 0;
}

Note that I've changed () to (void) in all the function declarations and definitions. This specifies that the function takes no arguments, rather than an unspecified number of arguments. The difference is that with double get_val(), the compiler (probably) won't complain if you call it incorrectly, for example get_val("foo").

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631