C “隐式函数声明”与函数原始版本之间的差异
我使用gcc4.8。我用睡眠编写了这样的代码C “隐式函数声明”与函数原始版本之间的差异,c,linux,sleep,C,Linux,Sleep,我使用gcc4.8。我用睡眠编写了这样的代码 int main(int argc, char *argv[]) { /* I know it's worong to pass a floating number to sleep * this is only for testing. */ sleep(0.001); return 0; } 我用gcc-Wall a.c-oa编译它,得到函数'sleep'[-Wimplicit f
int main(int argc, char *argv[])
{
/* I know it's worong to pass a floating number to sleep
* this is only for testing. */
sleep(0.001);
return 0;
}
我用gcc-Wall a.c-oa编译它,得到函数'sleep'[-Wimplicit function declaration]的警告隐式声明。然后我运行它,这个程序睡眠大约1秒,似乎睡眠细胞是0.001到1
然后我将代码更改为如下所示:
#include <unistd.h> /* add header file */
int main(int argc, char *argv[])
{
/* I know it's worong to pass a floating number to sleep
* this is only for testing. */
sleep(0.001);
return 0;
}
这一次它只睡0秒,好像睡0.001到0
这两个sleep不应该是相同的吗?在第一种错误的情况下,为sleep提供了一个真正的浮点值,因为它假设sleep的原型实际使用了一个双精度浮点值。sleep会将这个double的位表示解释为int,并等待这么多秒。你很幸运,这仅仅是1秒。在第二种情况下,浮点值被强制转换为整数,舍入为0。在第一种错误情况下,实际浮点值被赋予休眠,因为假定休眠原型的浮点值实际上是双精度的。sleep会将这个double的位表示解释为int,并等待这么多秒。你很幸运,这仅仅是1秒。在第二种情况下,浮点值被强制转换为整数,舍入为0。IMHO,请始终使用-Werror=隐式函数声明编译选项,以防止编译器/链接器的智能默认行为造成损害 通过将这两个案例编译成两个可执行文件sleep_include_no1错误案例,无include和sleep_include_yes第二个ok案例,使用include,我做了一些简单的测试:
## 'sleep' will invoke the 'nanosleep', and use strace to show real duration
$ strace ./sleep_include_no 2>&1 | grep nanosleep
clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=1, tv_nsec=0}, 0x7ffee0165970) = 0
$ strace ./sleep_include_yes 2>&1 | grep nanosleep
clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=0}, 0x7ffce92eedd0) = 0
从gdb的disas命令的输出截取asm代码:
IMHO,请始终使用-Werror=隐式函数声明编译选项,以防止编译器/链接器的智能默认行为造成损害 通过将这两个案例编译成两个可执行文件sleep_include_no1错误案例,无include和sleep_include_yes第二个ok案例,使用include,我做了一些简单的测试:
## 'sleep' will invoke the 'nanosleep', and use strace to show real duration
$ strace ./sleep_include_no 2>&1 | grep nanosleep
clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=1, tv_nsec=0}, 0x7ffee0165970) = 0
$ strace ./sleep_include_yes 2>&1 | grep nanosleep
clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=0}, 0x7ffce92eedd0) = 0
从gdb的disas命令的输出截取asm代码:
所以第一种情况就像把无符号int和t相加;一开始,更可能是int-sleepdoult,因为传统上隐式声明总是返回int。这可以追溯到早期版本的C。因此第一种情况类似于添加无符号int-sleepdoult;一开始,更可能是int-t,因为传统上隐式声明总是返回int。这可以追溯到早期版本的C。
$ cat my_lib.h
#ifndef _my_lib_h_
#define _my_lib_h_
long long get_i64_from_my_lib();
#endif
$ cat my_lib.c
#include "my_lib.h"
long long get_i64_from_my_lib() {
return 113840990519587; /* 6789 ABCD 0123 */
}
$ cat main.c
#include <stdio.h>
/* #include "my_lib.h" (without this include, the result is buggy) */
int main() {
long long i64 = get_i64_from_my_lib();
printf("%lld, %0lx\n", i64, i64);
}
$ gcc -g -c my_lib.c
$ ar -cq my_lib.a my_lib.o
$ gcc -g -o my_exe main.c my_lib.a ## emit implicit-function-declaration warning
## The returned type is not an expected i64, but a truncated i32. \
## When the returned value is less than 2^31, the function seems ok, \
## so it is an evil bug.
$ ./my_exe
-1412628189, ffffffffabcd0123