Is there a cross-platform way to reliably search for a stdout file descriptor using ctypes?

I have code that uses ctypes to try to determine if the file that sys.stdout stdout points to is sys.stdout . I know that on any POSIX-compatible system and even on Windows, it should be safe to assume that this is true if sys.stdout.fileno() == 1 , so my question is not how to do it in general.

In my code (which already uses ctypes for something not related to my question), I casually had something like:

 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: ... 

This works fine on Linux, so I haven’t thought much about it. It looked better and readable than hard coding 1 as a file descriptor. But after a few days, I found that my code did not work on OSX.

It turns out that OSX libc does not export a single character called 'stdout'. Instead, stdio.h has stdout, defined as:

 #define stdout __stdoutp 

If I change my code to c_void_p.in_dll(libc, '__stdoutp') , my code works as expected, but, of course, only OSX. Windows, it turns out, has a similar problem (at least when using MSVC).

I will probably just change my code to use 1 , but my question still stands out of curiosity if there is a cross-platform way to get the stdio pointer (as well as stdin and stderr ) without assuming it uses a POSIX compatible descriptor ?

+4
source share
2 answers

How often, when it comes to C, if you want compatibility, you have to go and look at the appropriate standard. Since you mention windows, I think you really don't need the POSIX standard, but rather C.

C99 section 7,19,1 defines stdout as a macro and therefore not a variable. This means that you cannot rely on its search with dlsym (which I assume to use in_dll). The actual expression can also be a function call or a fixed address. Perhaps not very likely, but it is possible ...

As stated in the comments, the fileno function, in turn, is defined by POSIX, not C. C does not have the concept of file descriptors. I think you better suggest POSIX and just check the value 1 that it indicates.

+3
source

If you're just interested in making everything work, rather than strictly adhering to standards (like me), you can find the β€œreal” name stdout by writing a simple C code snippet:

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

It produces the result:

 FILE* mystdout = __stdoutp; 

This means that you also need to try ctypes.c_void_p.in_dll(libc, '__stdoutp') to cover the darwin case.

+3
source

Source: https://habr.com/ru/post/1394473/


All Articles