Существует ли кроссплатформенный способ надежного поиска дескриптора файла stdout с помощью ctypes? - PullRequest
5 голосов
/ 03 февраля 2012

У меня есть код, который использует 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.

Оказывается, libc OSX не экспортирует ни один символ под названием 'stdout'. Вместо этого его stdio.h имеет стандартный вывод, определенный как:

#define stdout __stdoutp

Если я изменю свой код на c_void_p.in_dll(libc, '__stdoutp'), мой код будет работать как положено, но, конечно, это только для OSX. В Windows, как выясняется, есть похожая проблема (по крайней мере, при использовании MSVC).

Я, вероятно, просто изменю свой код на использование 1, но мой вопрос все еще стоит из любопытства, если есть кроссплатформенный способ получить указатель stdio (а также stdin и stderr ) без при условии , что он использует POSIX-совместимый дескриптор?

Ответы [ 2 ]

4 голосов
/ 03 февраля 2012

Как часто, когда дело доходит до C, если вы хотите совместимости, вам придется пойти и посмотреть соответствующий стандарт. Поскольку вы упоминаете о Windows, я полагаю, что вы на самом деле не хотите стандарт POSIX, а скорее стандарт C.

C99 раздел 7,19,1 определяет stdout как макрос, и, следовательно, не переменную. Это означает, что вы не можете рассчитывать на его поиск с помощью dlsym (который, я предполагаю, использует in_dll). Фактическое выражение также может быть вызовом функции или фиксированным адресом. Возможно, не очень вероятно, но это возможно ...

Как сказано в комментариях, функция fileno в свою очередь определяется POSIX, а не C. C не имеет понятия файловых дескрипторов. Я думаю, вам лучше принять POSIX и просто проверить значение 1, которое оно указывает.

3 голосов
/ 20 октября 2014

Если вы просто заинтересованы в том, чтобы все работало, а не строго придерживались стандартов (как я), вы можете найти «настоящее» имя stdout, написав простой фрагмент кода 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'), чтобы раскрыть дело Дарвина.

...