gcc (GCC) 4.6.3
c89
我正在尝试使用usleep
.但是,我不断收到以下警告:
功能usleep的隐式声明
我已经包含了unistd.h
头文件。
手册页提到了一些关于这一点的内容。但我不确定我是否理解它:
usleep():
Since glibc 2.12:
_BSD_SOURCE ||
(_XOPEN_SOURCE >= 500 ||
_XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED) &&
!(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
Before glibc 2.12:
_BSD_SOURCE || _XOPEN_SOURCE >= 500 || _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED
但不确定我如何处理上述内容?
该列表是定义usleep
的先决条件。它基本上是一个类似 C 的表达式,涉及#define
变量,在包含头文件之前必须为 true。
头文件本身只会在通常是大量#ifdef
语句巢中定义usleep
,开发人员已经花时间告诉您需要做什么,这样您就不必花费数小时试图自己弄清楚:-(
假设您使用的是 2.12 或更高版本的glibc
,这意味着您必须:
- 声明_BSD_SOURCE;或
- 声明其他三件事的复杂组合,我不会费心去解码。
可能最简单的解决方法是简单地使用 gcc -D _BSD_SOURCE
或 put 进行编译:
#define _BSD_SOURCE
在包含头文件之前的代码中,该文件为您提供usleep
.
您可能希望在任何包含之前定义这些内容,以防各种头文件之间存在依赖关系。
这可能有效:在 Linux 上使用 gcc 编译时添加-std=gnu99
。
例:
arm-linux-gcc -lpthread -std=gnu99 -o test ArmLinuxDataPipe1.2.1.c
Tl;dr
如果需要获取使用 usleep()
进行编译的旧代码,请将以下行添加到包含在任何其他库之前的头文件中:
#define _XOPEN_SOURCE 600
#define _POSIX_C_SOURCE 200112L
或者将编译器标志-std=c11 -D_XOPEN_SOURCE=600 -D_POSIX_C_SOURCE=200112L
添加到生成文件。
这告诉环境您的程序使用此旧版本的 UNIX API,其中usleep()
未被弃用。
或者(如果这肯定是新代码(将usleep()
替换为nanosleep()
,为您的库版本设置适当的功能测试宏,并检查您的代码库是否有其他位腐烂。
在 Linux 上,您可以在 man feature_test_macros
中检查您的库支持的 _XOPEN_SOURCE
和_POSIX_C_SOURCE
值。
全貌
更长的答案:这是怎么回事。
历史上有几种不同的 UNIX 标准,最终每个人都想到的最佳实践是让代码指定它所针对的 UNIX API 版本。 程序员通过定义功能测试宏来做到这一点。
UNIX最早的分裂之一是AT&T的System V和加州大学的伯克利标准发行版(BSD(。 由于System V是正式版本,它的行为成为默认版本,而BSD Unix是最早的自由软件之一,并在许多大学中使用,因此看到遗留代码声明_BSD_SOURCE
比_SVID_SOURCE
更常见。 _BSD_SOURCE
宏特别尝试在四十多年的时间里启用来自各种不同操作系统的扩展。 有时,它甚至被用作非标准扩展的包罗万象。 这两个宏都已弃用,与当前接受的答案相反,您永远不应该在新代码中使用任何一个宏。
在本世纪,有两个UNIX标准,POSIX,它成为IEEE标准,以及来自Open Group(X/Open(的单一Unix规范(SUS(。 X/Open SUS是POSIX的超集,也是你通常写的东西。 过去,您可以声明许多不同的功能测试宏来启用这些标准的当前版本,并且仍然支持这些宏以实现向后兼容性。您可以在粘贴的条件中看到其中一些,但在编写新代码时无需担心它们。 代码检查的一个宏,_XOPEN_SOURCE_EXTENDED
,现在已经过时了,但历史上选择了1995年的SUS版本。
理论上,在任何现代版本的 UNIX 或 Linux 上设置正确的功能测试宏是_XOPEN_SOURCE
。 您应该查找库支持的最新版本号。 在实践中,我认为定义_POSIX_C_SOURCE
也是谨慎的防御性编码,以保证没有其他人可以不一致地设置它并破坏您的代码。 您的问题就是一个很好的例子:如果您将_XOPEN_SOURCE
设置为向后兼容,但_POSIX_C_SOURCE
工具链中的其他地方设置为更新的版本,则更高版本的_POSIX_C_SOURCE
将优先,usleep()
将不起作用。
所以,这些条件的意思是,usleep()
不是一个POSIX函数,而是曾经存在于一些类似BSD的操作系统上,因此在1995年进入了SUS。 它在 2008 年被弃用,从那时起选择任何版本的 POSIX 或 SUS 都会主动禁用它。 因此,如果您选择 SUS 的版本 500 或 600(另一个过时的同义词也打开它(,则会启用它,但如果选择任何最新版本的 POSIX 或 SUS,则会弃用它。 如果您选择"随心所欲"选项,它们也会启用,但这是一个坏主意。
有关现在在 C 语言中更好的睡眠演示,请参阅我的eRCaGuy_hello_world存储库,例如:
- sleep_nanosleep.c
- sleep_nanosleep_minimum_time_interval.c
- timinglib_sleep_and_sleep_until.c
- timinglib.h
- timeinglib.c
nanosleep()
演示:如何从nanosleep()
编写自己的sleep_us()
函数
将以下内容添加到代码的顶部,#define _POSIX_C_SOURCE 199309L
部分位于#include <time.h>
之前,以便它将引入<time.h>
的nanosleep()
函数!
// This line **must** come **before** including <time.h> in order to bring in
// the POSIX functions such as `clock_gettime()`, `nanosleep()`, etc., from
// `<time.h>`!
#define _POSIX_C_SOURCE 199309L
// For `nanosleep()`:
#include <time.h>
然后改用nanosleep()
来创建自己的sleep_us()
函数,以休眠设定的微秒数:
void sleep_us(unsigned long microseconds)
{
struct timespec ts;
ts.tv_sec = microseconds / 1000000ul; // whole seconds
ts.tv_nsec = (microseconds % 1000000ul) * 1000; // remainder, in nanoseconds
nanosleep(&ts, NULL);
}
为了在 Linux Ubuntu 上编译和运行,我创建了一个 sleep_test.c 文件并使用:
gcc -Wall -g3 -std=c11 -o sleep_test sleep_test.c && ./sleep_test
引用:
- (这是故意循环参考:请参阅我在此答案下的评论(:是否有 C 到毫秒的替代睡眠函数?
- http://man7.org/linux/man-pages/man2/nanosleep.2.html
- 提到:
_POSIX_C_SOURCE >= 199309L
相关:
- 我的另一个答案是使用 POSIX 定时函数(例如:
clock_gettime()
:以微秒为单位获取 C 格式的时间戳?
更进一步:
- 尝试使用单调时钟和标志
TIMER_ABSTIME
clock_nanosleep()
,以实现类似于 FreeRTOSvTaskDelayUntil()
功能的功能,以实现精确和可重复的周期性操作。- 通过在
#include <time.h>
之前使用#define _POSIX_C_SOURCE 200112L
来增加 POSIX 版本,以便访问clock_nanosleep()
。
- 通过在
问题的答案:用 #define _BSD_SOURCE
或#define _GNU_SOURCE
对于那些有错误的人
warning: #warning "_BSD_SOURCE and _SVID_SOURCE are deprecated, use _DEFAULT_SOURCE" [-Wcpp]
# warning "_BSD_SOURCE and _SVID_SOURCE are deprecated, use _DEFAULT_SOURCE"
^~~~~~~
使用后#define _BSD_SOURCE
请尝试使用
#define _GNU_SOURCE
注意:在包含为您提供usleep()
的标题之前使用,即在包含unistd.h
之前
使用 nanosleep(( 反而对我有用。
在相关说明中:usleep(( 自 POSIX-2008 以来已被删除,并且 建议改用 nanosleep((。