是否有跨平台的方法通过ctypes可靠地找到stdout文件描述符?
我有一段代码,使用ctypes来判断sys.stdout
指向的文件是否真的是stdout
。我知道在任何符合POSIX标准的系统上,甚至在Windows上,如果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特有的。结果发现,Windows也有类似的问题(至少在使用MSVC时是这样)。
我可能会把代码改成直接使用1
,但出于好奇,我还是想问有没有一种跨平台的方法来获取stdio
指针(同样适用于stdin
和stderr
),而不需要假设它使用的是符合POSIX标准的描述符?
2 个回答
如果你只是想让事情正常运作,而不是严格遵循标准(就像我一样),你可以通过写一段简单的C代码来找到标准输出(stdout)的“真实”名称:
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系统的情况。
在谈到C语言的时候,常常需要查看相关的标准来确保兼容性。既然你提到了Windows,我猜你其实不想用POSIX标准,而是想用C语言的标准。
C99标准的第7.19.1节定义了stdout是一个宏,而不是一个变量。这意味着你无法通过dlsym(我猜in_dll使用的是这个)来找到它。实际上,stdout可能只是一个函数调用或者是一个固定的地址。虽然这种情况不太常见,但确实是有可能的……
正如评论中所说,fileno函数是由POSIX定义的,而不是C语言。C语言并没有文件描述符的概念。我觉得你最好假设使用POSIX,并且直接检查值1,因为这是它所规定的。