为什么 sqrt 函数不适用于通过用户输入获取的值?
Why does sqrt function not work for values taken through user input?
以下代码:
#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
、sqrtl
如果我没记错的话)。此外,无论我采用 long long int
还是 double
类型的 a
,上述代码都会失败。所以,问题可能不相关。
此外,关于另一个 linked question,对于不断定义的值,我没有发生错误,而恰好是链接问题的情况。
那是什么原因呢?为什么常量值适用于 sqrt
,而可变用户输入值则不行?
就像评论中提到的那样,您没有 link反对 libm
所以 sqrt
在 link 时未定义。
Why would a constant value work for sqrt
, while a variable user input value won't?
因为 GCC 将 sqrt
识别为 builtin function 并且能够在编译时计算编译时常量的平方根,并完全放弃对 sqrt
的调用,从而避免随后的 linker 错误。
The ISO C90 functions ... sqrt
, ... are all recognized as built-in functions unless -fno-builtin
is specified (or -fno-builtin-
function
is specified for an individual function).
如果您要添加 -fno-builtin-sqrt
,无论您将什么传递给 sqrt
,您都会看到 linker 错误。
stdlib.h
和 stdio.h
中的函数在 libc.so
中有实现(或 libc.a
用于静态 linking),即 link默认进入可执行文件(就像指定了 -lc
)。
可以指示 GCC 使用 -nostdlib
或 -nodefaultlibs
选项避免这种自动 link。
math.h 中的函数在 libm.so
中有实现(或 libm.a
用于静态 linking),默认情况下不 link 编辑 libm .
基本上,C++ 运行时 libstdc++
需要 libm
,所以如果你用 GCC (g++) 编译 C++ 程序,你会自动得到 libm
linked .
以下代码:
#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
、sqrtl
如果我没记错的话)。此外,无论我采用 long long int
还是 double
类型的 a
,上述代码都会失败。所以,问题可能不相关。
此外,关于另一个 linked question,对于不断定义的值,我没有发生错误,而恰好是链接问题的情况。
那是什么原因呢?为什么常量值适用于 sqrt
,而可变用户输入值则不行?
就像评论中提到的那样,您没有 link反对 libm
所以 sqrt
在 link 时未定义。
Why would a constant value work for
sqrt
, while a variable user input value won't?
因为 GCC 将 sqrt
识别为 builtin function 并且能够在编译时计算编译时常量的平方根,并完全放弃对 sqrt
的调用,从而避免随后的 linker 错误。
The ISO C90 functions ...
sqrt
, ... are all recognized as built-in functions unless-fno-builtin
is specified (or-fno-builtin-
function
is specified for an individual function).
如果您要添加 -fno-builtin-sqrt
,无论您将什么传递给 sqrt
,您都会看到 linker 错误。
stdlib.h
和 stdio.h
中的函数在 libc.so
中有实现(或 libc.a
用于静态 linking),即 link默认进入可执行文件(就像指定了 -lc
)。
可以指示 GCC 使用 -nostdlib
或 -nodefaultlibs
选项避免这种自动 link。
math.h 中的函数在 libm.so
中有实现(或 libm.a
用于静态 linking),默认情况下不 link 编辑 libm .
基本上,C++ 运行时 libstdc++
需要 libm
,所以如果你用 GCC (g++) 编译 C++ 程序,你会自动得到 libm
linked .