Reputation: 8699
I have one participant in a basic C course who created a mystery. The task is to write a function double square_to(double *)
which just squares the number in-place and also returns the result.
Stripped down, the code looks like this:
main.c
:
#include "mymath.h"
#include <stdio.h>
int main() {
double t = 5;
double *p;
double m;
p = &t;
m = square_to(p);
printf("%f\n%f\n", t, m);
return 0;
}
mymath.h
:
#ifndef MYMATH_H
#define MYMATH_H
double square_to(double *p);
#endif
mymath.c
:
#include "mymath.h"
#include <stdio.h>
double square_to(double *p) {
*p = (*p) * (*p);
return *p;
}
Compile flags are:
-Wall -pedantic -o day5 main.c mymath.c
I do not see anything wrong with it. It also works just fine with Clang and GCC on his Ubuntu and my Fedora. The program outputs 25.000
twice in each case.
The part where it gets strange is when his original files are used. There are a couple of other functions from other parts of the course in the mymath.c
. Those function compile apparently. In the main.c
, his GCC 5.4 warns about the implicit declaration of square_to
. When running the program, it outputs 25.000
and some random number which appears to be an integer. Running it again outputs a different number. Therefore this is no casting problem, it is a real undefined behavior.
Compiling the same code with Clang (just exchanging gcc
with clang
in the command line, -Wall
and -Wpedantic
active), it works just fine, giving 25.000
in every case. This is a red flag as standard compliant code should compile just fine with both compilers. On my Fedora installation it works with GCC 6.2.1.
The full code is in this gist.
I have no idea why the full code changes the behavior of the square_to
function. What is wrong with the full program?
Before I left the tutorial I asked the student to download the code in the gist and compile it. He did so with gcc -Wall -pedantic main.c mymath.c
and it compiled without errors. Running it gave 25.000 25.000
as it should be.
So the problem is nowhere in any code that I have. There has to be something very strange in the directory that he works from. I have double checked the path in the editor and the terminal, I also did a less main.c
and it was the correct one.
There is no way to answer this question now as I don't have anything to reproduce the problem. The participant also had various other similar problems. See those here:
There it can be seen that a function somehow is called with double *
although there are only int
in the functions. Then gcc
points to a declaration which supposedly conflicts and it is the very same prototype.
I'm for closing this question because nothing more can be learned without having access to the particular environment that the participant had. He just said that he would start in a new directory tomorrow. If it still persists, I will collect the whole directory.
Upvotes: 1
Views: 555
Reputation: 6752
From: Implicit function declarations sometimes work in C?
If the expression that precedes the parenthesized argument list in a function call consists solely of an identifier, and if no declaration is visible for this identifier, the identifier is implicitly declared exactly as if, in the innermost block containing the function call, the declaration
extern int identifier();
appeared.
Since main.c thinks the function should return an int
, that is what you get (later cast to a double in the assignment).
On Intel and AMD processors running Linux, integers are returned in rax
and doubles are returned in the floating point registers. So my guess is that in this case, the integer you are seeing is whatever happened to be in the rax
register when the function returned.
But this is just a guess, undefined behaviour is undefined.
Since there seems to be some confusion: If you get a warning about implicit declarations, that means that GCC didn't see any valid declarations before the usage. Either that, or your compiler is broken.
Properly declaring int-returning functions in C<99 is optional but highly recommended.
Upvotes: 1