mkdtemp需要unistd.h的_DARWIN_C_源

mkdtemp需要unistd.h的_DARWIN_C_源,c,linux,macos,posix,C,Linux,Macos,Posix,我有点困惑。我有一个我用它编译的项目 CFLAGS=-g -O2 -Wall -Wextra -Isrc/main -pthread -rdynamic -DNDEBUG $(OPTFLAGS) -D_FILE_OFFSET_BITS=64 -D_XOPEN_SOURCE=700 现在我想使用mkdtemp,因此包括unistd.h char *path = mkdtemp(strdup("/tmp/test-XXXXXX")); 在MacOSX上,编译提供了一些警告 warning: im

我有点困惑。我有一个我用它编译的项目

CFLAGS=-g -O2 -Wall -Wextra -Isrc/main -pthread -rdynamic -DNDEBUG $(OPTFLAGS) -D_FILE_OFFSET_BITS=64 -D_XOPEN_SOURCE=700
现在我想使用
mkdtemp
,因此包括
unistd.h

char *path = mkdtemp(strdup("/tmp/test-XXXXXX"));
在MacOSX上,编译提供了一些警告

warning: implicit declaration of function ‘mkdtemp’
warning: initialization makes pointer from integer without a cast
但是编译通过了。当
mkdtemp
返回非空路径访问时,它会导致EXC\u BAD\u访问

问题1:模板为
strdup()
ed,结果为非空。这究竟是如何导致EXC\u坏访问的?

现在在兔子洞的下面。让我们摆脱这些警告吧。检查
unistd.h
我发现前处理器隐藏了声明

#if     !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
...
char    *mkdtemp(char *);
...
#endif
-D_DARWIN_C_SOURCE
添加到构建中可以消除所有问题,但留给我的是特定于平台的构建。10.6手册页只是说

 Standard C Library (libc, -lc)
 #include <unistd.h>
问题2:那么您将如何解决这个问题?


我找到的唯一修复方法是在
unistd.h
包含之前添加
#undef
\u POSIX\u C\u源代码……但这感觉像是一个丑陋的黑客行为。

您在这里问了两个问题,我只想回答第一个问题:

问题1:模板是strdup()的,结果是非空的。这究竟是如何导致EXC\u坏访问的

正如上面的警告告诉您的:

警告:函数“mkdtemp”的隐式声明

这意味着它找不到
mkdtemp
的声明。根据C规则,这是允许的,但它假设函数返回int

警告:初始化将指针从整数转换为不带强制转换的整数

您已经告诉编译器“我有一个返回int的函数,我想将值存储在char*中”。它警告你这是个坏主意。您仍然可以这样做,因此它可以编译

但是想想在运行时会发生什么。链接到的实际代码返回64位字符*。然后,代码将其视为32位int,必须将其转换为64位char*。这样做的可能性有多大


这就是为什么您不忽略警告。

现在来看第二个问题:

问题2:那么你将如何解决这个问题

您的问题是您显式地传递了-D_XOPEN_SOURCE=700,但您使用的是一个函数mkdtemp,该函数在您要求的标准中没有定义。这意味着你的代码不应该工作。它在linux上工作的事实并不意味着您的代码是正确的或可移植的,只是您碰巧在一个平台上获得了好运

因此,有两种非常明显的方法来解决这个问题:

  • 如果您想使用_XOPEN_SOURCE=700,请重写代码以仅使用该标准中的函数

  • 如果您只是添加了_XOPEN_SOURCE=700作为一种您并不真正理解的黑客,因为它似乎解决了linux上的其他一些问题,请找到在linux上解决该问题的正确方法


  • 结果可能是某个平台上有一个bug,所以没有正确的方法来修复它。或者,更可能的情况是,您正在使用非标准函数的组合,这些函数可以在不同的平台上压缩,每个平台上都有一组不同的标志。在这种情况下,您的Makefile(或任何驱动构建的东西)必须在不同的平台上向编译器传递不同的标志。这对于跨平台项目来说非常典型;很高兴您只需要担心一个标志,并且没有构建3000行的autoconf。

    mkdtemp不是基本的POSIX——根据它在扩展API中的描述。Segfault:你确定你传递的是char*而不是const char*?我知道
    mkdtemp
    不是基本POSIX。但似乎
    \u XOPEN\u SOURCE
    导致定义
    \u POSIX\u C\u SOURCE
    。仍然希望使用
    mkdtemp
    ftw
    API。至于
    const char*
    请参见上文。它是通过
    strdup
    复制的文本。所以这应该没问题。@H2CO3呃,那里的CX实际上意味着它在POSIX中,而不是在ANSI C中。问题是OSX显然不支持它添加的POSIX版本。我只添加了
    \u XOPEN\u SOURCE
    ,因为我想使用
    ftw
    API。显然,这也迫使
    \u POSIX\u C\u SOURCE
    。什么是标准?linux的手册页有很多信息……最近的OpenGroup标准()的第1节和第2.2节也是如此。但一切都在一个地方?可悲的是,据我所知不是这样。(此外,linux和OS X都包含许多扩展,这些扩展可能在下一个标准中超出了它们当前支持的扩展,等等)同时,FTW在XOpen 7中并不是新的—事实上,它在XOpen 7中被标记为过时—所以我不确定这是引入它的正确方式。首先—感谢链接!非常有用<代码>ftw是否标记为已过时?叹息开罐——虫子——到处都是。最初我使用的是
    fts
    API,但在Linux上编译时,我最终遇到了
    #error“不能与-D_FILE_OFFSET_BITS==64”
    IIRC一起使用,fts是一个BSD扩展,Linux已经复制了它,但它仍然没有登录到POSIX中,这意味着即使它起作用,您最终可能会得到“可移植”到Linux和*BSD的代码(包括OSX)但是没有其他地方,这是欺骗你自己的好方法…这里令人悲伤的答案是没有完全可移植的替代方案。这意味着你将不得不进行一些可移植性黑客攻击。在Makefile中进行一行平台检查比大多数项目必须处理的痛苦要小得多…考虑到我只关心Linux和OS X在这个阶段-现在还可以。不使用文件偏移量是一个可以让我逃离“地狱”的妥协。谢谢你们的输入,伙计们。因为另一个问题似乎没有简单的答案,我接受这个问题。
    warning: ‘struct FTW’ declared inside parameter list
    warning: its scope is only this definition or declaration, which is probably not what you want
    In function ‘tmp_remove’:
    warning: implicit declaration of function ‘nftw’
    error: ‘FTW_DEPTH’ undeclared (first use in this function)
    error: (Each undeclared identifier is reported only once
    error: for each function it appears in.)
    error: ‘FTW_PHYS’ undeclared (first use in this function)