2

我有点不解。我有我编译的项目

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()ed,结果非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在包含之前 _POSIX_C_SOURCE unistd.h...但这感觉就像一个丑陋的黑客。

4

2 回答 2

2

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

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

正如上面的警告告诉你的那样:

警告:函数“mkdtemp”的隐式声明</p>

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

警告:初始化使指针从整数而不进行强制转换

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

但是想想运行时会发生什么。您链接到的实际代码返回 64 位 char*。然后您的代码将其视为必须转换为 64 位 char* 的 32 位 int。这有多大可能起作用?

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

于 2012-07-11T23:57:21.067 回答
0

现在是第二个问题:

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

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

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

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

  2. 如果您只是将 _XOPEN_SOURCE=700 添加为一个您并不真正理解的 hack,因为它似乎解决了 linux 上的一些其他问题,请找到在 linux 上解决该问题的正确方法。

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

于 2012-07-12T00:02:52.247 回答