我使用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函数A。C -o a“编译,得到警告”隐式声明函数‘-Wall’-Wimplicit function --o“。然后我运行它,这个程序休眠了大约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.001秒,看起来像是休眠楼层0.001到0。
这两个睡眠不应该是一样的吗?
发布于 2013-05-03 22:18:32
在第一种(错误的)情况下,一个实际的浮点值被赋予休眠状态,因为假设sleep的原型接受一个浮点值(实际上是一个double )。sleep会将这个double的比特表示解释为一个int,并等待这么多秒。您很幸运,这只有1秒。在第二种情况下,浮点值被强制转换为舍入为0的int。
发布于 2020-11-30 14:21:02
IMHO,请始终使用-Werror=implicit-function-declaration编译选项以防止编译器/链接器的智能默认行为造成的损坏。
通过将这两个案例编译成两个可执行文件sleep_include_no(第一个错误案例,不包含)和sleep_include_yes(第二个正常案例,包含),我做了一些简单的测试:
## '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代码:
/* 1st wrong case (without include), compiler/linker's default behavior, \
an immediate constant '0x1' is set into %eax as parameter of sleep */
=> 0x0000555555555141 <+8>: movsd 0xebf(%rip),%xmm0 # 0x555555556008
0x0000555555555149 <+16>: movsd %xmm0,-0x8(%rbp)
0x000055555555514e <+21>: mov -0x8(%rbp),%rax
0x0000555555555152 <+25>: movq %rax,%xmm0
0x0000555555555157 <+30>: mov $0x1,%eax
0x000055555555515c <+35>: call 0x555555555030 <sleep@plt>
/* 2nd ok case (with include), \
the 'cvttsd2si' instruction is something like cast double to int */
=> 0x0000555555555141 <+8>: movsd 0xebf(%rip),%xmm0 # 0x555555556008
0x0000555555555149 <+16>: movsd %xmm0,-0x8(%rbp)
0x000055555555514e <+21>: movsd -0x8(%rbp),%xmm0
0x0000555555555153 <+26>: cvttsd2si %xmm0,%rax
0x0000555555555158 <+31>: mov %eax,%edi
0x000055555555515a <+33>: call 0x555555555030 <sleep@plt>所以编译器/链接器只是让它工作,但可能不是您所期望的。我认为这是因为编译器有太多的遗留特性需要处理和兼容性考虑,我们不应该责怪它。作为一名程序员,我唯一能做的就是使用-Werror=implicit-function-declaration发出强制警报。
P.S.分享一个通过不包括用户定义的API头文件并忽略函数警告的隐式声明而引发的血腥生产错误。以下是演示代码(3个源文件):
$ 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, ffffffffabcd0123https://stackoverflow.com/questions/16361006
复制相似问题