我有一个基础C课程的参与者创造了一个谜。我们的任务是编写一个函数double square_to(double *)
,它只是将数字对齐,并返回结果。
剥离,代码如下所示:
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;
}
编译标志是:
-Wall -pedantic -o day5 main.c mymath.c
我认为没有任何问题。在他的Ubuntu和我的Fedora上,Clang和GCC也可以正常工作。该程序在每种情况下输出25.000
两次。
奇怪的部分是使用原始文件的时候。 mymath.c
中课程的其他部分还有其他一些功能。那些函数显然是编译的。在main.c
中,他的GCC 5.4警告square_to
的隐含声明。运行程序时,它会输出25.000
和一些随机号,它看起来是一个整数。再次运行它会输出不同的号码。因此,这不是铸造问题,它是一种真正的未定义行为。
使用Clang编译相同的代码(仅在命令行中将gcc
与clang
交换,-Wall
和-Wpedantic
处于活动状态),它运行正常,给出{{ 1}}在每种情况下。这是一个红旗,因为标准兼容代码应该与两个编译器编译得很好。在我的Fedora安装上,它适用于GCC 6.2.1。
完整代码位于此gist。
我不知道为什么完整的代码会改变25.000
函数的行为。整个计划有什么问题?
在我离开教程之前,我让学生在gist中下载代码并编译它。他使用square_to
这样做,并且编译时没有错误。运行它会给它gcc -Wall -pedantic main.c mymath.c
。
所以我的任何代码都没有问题。在他工作的目录中必须有一些非常奇怪的东西。我已经仔细检查了编辑器和终端中的路径,我也做了一个25.000 25.000
,这是正确的。
现在没有办法回答这个问题,因为我没有任何东西可以重现这个问题。参与者还有其他各种类似的问题。看到这里的那些:
虽然函数中只有less main.c
,但可以看到函数以某种方式调用double *
。然后int
指向一个声称存在冲突的声明,它是完全相同的原型。
我要关闭这个问题,因为如果没有访问参与者所具有的特定环境,就无法学到更多。他只是说明天他会在一个新目录中开始。如果它仍然存在,我将收集整个目录。
答案 0 :(得分:1)
来自:Implicit function declarations sometimes work in C?
如果表达式位于括号中的参数列表之前 函数调用仅由标识符组成,如果没有声明 对于此标识符是可见的,隐式声明标识符 就像在包含函数调用的最里面的块中一样 宣言
extern int identifier();
出现。
因为main.c认为函数应该返回一个int
,这就是你得到的(后来转换为赋值中的double)。
在运行Linux的Intel和AMD处理器上,整数在rax
中返回,并且在浮点寄存器中返回双精度数。所以我的猜测是,在这种情况下,你看到的整数是函数返回时在rax
寄存器中发生的任何事情。
但这只是猜测,未定义的行为未定义。
由于似乎存在一些混淆:如果您收到有关隐式声明的警告,这意味着GCC在使用之前没有看到任何有效的声明。要不然,或者你的编译器坏了。
在C <99中正确地声明返回函数是可选的,但强烈建议。