6

我有一些代码使用 ctypes 来尝试确定所指向的文件sys.stdout是否实际上是 stdout. 我知道在任何符合 POSIX 的系统上,甚至在 Windows 上,都应该安全地假设这是真的 if sys.stdout.fileno() == 1,所以我的问题不是一般如何做到这一点。

在我的代码中(它已经使用 ctypes 来处理与我的问题无关的事情)我不小心有类似的东西:

libc = ctypes.CDLL(ctypes.util.find_library('c'))
real_stdout = libc.fileno(ctypes.c_void_p.in_dll(libc, 'stdout'))
if sys.stdout.fileno() == real_stdout:
    ...

这在 Linux 上运行得非常好,所以我并没有考虑太多。1它看起来比硬编码作为文件描述符更好,更易读。但几天后我发现我的代码无法在 OSX 上运行。

事实证明 OSX 的 libc 不会导出任何名为“stdout”的符号。相反,它的 stdio.h 将 stdout 定义为:

#define stdout __stdoutp

如果我将我的代码更改为c_void_p.in_dll(libc, '__stdoutp')我的代码按预期工作,但这当然是 OSX-only。事实证明,Windows 也有类似的问题(至少在使用 MSVC 的情况下)。

我可能只是将我的代码更改为 use 1,但出于好奇,我的问题仍然存在,如果有一种跨平台的方式来获取stdio指针(同样是stdinand stderr)而不假设它使用的是符合 POSIX 的描述符?

4

2 回答 2

4

与 C 语言一样,如果您想要兼容性,则必须查看相关标准。既然您提到了 Windows,我猜您实际上并不想要 POSIX 标准,而是 C 标准。

C99 第 7,19,1 节将 stdout 定义为宏,因此不是变量。这意味着您无法依靠使用 dlsym 找到它(我假设 in_dll 使用它)。实际的表达式也可以是函数调用或固定地址。也许不太可能,但有可能……

正如评论中所说,fileno 函数又是由 POSIX 定义的,而不是由 C 定义的。C 没有文件描述符的概念。我认为您最好假设 POSIX 并仅检查它指定的值 1。

于 2012-02-02T22:34:49.343 回答
3

如果您只是对使事情正常工作感兴趣,而不是严格遵守标准(像我一样),您可以通过编写一个简单的 C 代码片段来找到标准输出的“真实”名称:

echo -e '#include <stdio.h>\nFILE* mystdout = stdout;' > test.c
cpp test.c | tail

给你输出:

FILE* mystdout = __stdoutp;

这意味着您还需要尝试ctypes.c_void_p.in_dll(libc, '__stdoutp')涵盖 darwin 的情况。

于 2014-10-20T18:45:51.733 回答