对于unistd.h,mkdtemp需要_DARWIN_C_SOURCE

时间:2012-07-11 20:18:59

标签: 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: implicit declaration of function ‘mkdtemp’
warning: initialization makes pointer from integer without a cast

但是通过编译。虽然mkdtemp确实返回非NULL路径,但访问它会产生EXC_BAD_ACCESS。

问题1:模板为strdup(),结果为非NULL。这怎么会导致EXC_BAD_ACCESS?

现在兔窝洞越来越远了。让我们摆脱警告。检查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>

从构建中删除_XOPEN_SOURCE可以在OSX上运行但是在Linux下无法编译

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)

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

我发现的唯一解决办法就是在#undef包含之前unistd.h _POSIX_C_SOURCE ...但这感觉就像一个丑陋的黑客。

2 个答案:

答案 0 :(得分:2)

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

  

问题1:模板是strdup()ed,结果是非NULL。这怎么会导致EXC_BAD_ACCESS?

正如上面的警告告诉你:

  

警告:隐式声明函数'mkdtemp'

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

  

警告:初始化使得整数指针不带强制转换

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

但请考虑一下运行时会发生什么。您链接的实际代码返回64位char *。然后你的代码将它视为32位int,它必须转换为64位char *。这有多大可能起作用?

这就是你不忽视警告的原因。

答案 1 :(得分:0)

现在提出第二个问题:

  

问题2:那你怎么解决这个问题?

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

因此,有两种相当明显的方法可以解决这个问题:

  1. 如果您想使用_XOPEN_SOURCE = 700,请将您的代码重写为仅使用该标准中的函数。

  2. 如果你只是添加_XOPEN_SOURCE = 700作为你不太懂的黑客,因为它似乎解决了linux上的其他一些问题,找到正确的方法来修复linux上的问题。

  3. 可能会发现某个平台或其他平台上存在错误,因此无法正确修复它。或者,更有可能的是,您使用的是非标准函数的组合,这些函数可以在不同的平台上进行挤压,每个平台上都有一组不同的标志。在这种情况下,您的Makefile(或任何驱动构建)必须在不同平台上将不同的标志传递给编译器。这对于跨平台项目来说非常典型;只是很高兴你只需要担心一面旗帜,并且不会建造3000行的autoconf。