以下代码:
#include <stdio.h>
#include <math.h>
int main(void)
{
long long int a;
scanf("%lld", &a);
printf("%lf", sqrt(a));
return 0;
}
给出输出:
source_file.c: In function ‘main’:
source_file.c:9:5: warning: ignoring return value of ‘scanf’, declared with attribute warn_unused_result [-Wunused-result]
scanf("%lld", &a);
^
/tmp/ccWNm2Vs.o: In function `main':
source.c:(.text.startup+0x65): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status
但是,如果我执行long long int a = 25;
并删除scanf
语句,或者只是执行sqrt(25)
,则它们都可以工作(正确地提供输出5.000000
)。
我检查了this question,但是它用于C ++,并且使用函数重载,而afaict C没有函数重载(这就是为什么我们有sqrtf
,sqrt
,{{1} }(如果我没看错)。此外,无论我采用sqrtl
还是long long int
类型的double
,以上代码均失败。所以问题可能不相关。
另外,对于其他linked question,对于恒定定义的值,我也没有发生错误,相反,链接的问题正是这种情况。
那是什么原因?为什么常量值对a
有效,而可变的用户输入值无效?
答案 0 :(得分:4)
就像评论中提到的那样,您尚未针对libm
进行链接,因此sqrt
在链接时未定义。
为什么常量值对
sqrt
有效,而可变的用户输入值无效?
因为GCC将sqrt
识别为builtin function,并且能够在编译时评估编译时常量的平方根,并且完全放弃了对sqrt
的调用,因此避免了随后的链接器错误。
除非指定了
sqrt
(或-fno-builtin
-fno-builtin-
,否则ISO C90函数...function
,...都被识别为内置函数。 是为单个功能指定的)。
如果要添加-fno-builtin-sqrt
,则无论传递给sqrt
的内容如何,都将看到链接器错误。
答案 1 :(得分:1)
stdlib.h
和stdio.h
中的函数在libc.so
中实现(对于静态链接,则为libc.a
),默认情况下链接为可执行文件(就像{{1 }})。
可以指示GCC避免使用-lc
或-nostdlib
选项进行自动链接。
math.h中的函数在-nodefaultlibs
(或对于静态链接为libm.so
)中具有实现,并且默认情况下未链接libm。
基本上,C ++运行时libm.a
需要libstdc++
,因此,如果使用GCC(g ++)编译C ++程序,则会自动获得libm
的链接。