6

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 を使用している場合)。

私はおそらく自分のコードを use に変更するだけですが、POSIX準拠の記述子を使用していると仮定せずにポインター1を取得するクロスプラットフォームの方法がある場合、私の質問は好奇心から立っています(同様に and ) ?stdiostdinstderr

4

2 に答える 2

4

Cに関してはよくあることですが、互換性が必要な場合は、関連する標準を調べる必要があります。Windowsについて言及しているので、実際にはPOSIX標準ではなく、C標準が必要だと思います。

C99 セクション 7,19,1 では、stdout をマクロとして定義しているため、変数ではありません。つまり、dlsym (in_dll が使用すると仮定) を使用してそれを見つけることに頼ることはできません。実際の式は、関数呼び出しでも固定アドレスでもかまいません。可能性は低いかもしれませんが、可能性はあります...

コメントで述べたように、 fileno 関数は C ではなく POSIX で定義されています。C にはファイル記述子の概念がありません。POSIXを想定して、それが指定する値1をチェックする方がよいと思います。

于 2012-02-02T22:34:49.343 に答える
3

(私のように) 厳格な標準への準拠ではなく、物事を機能させることに単に興味がある場合は、単純な 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')これは、ダーウィンのケースもカバーしようとする必要があることを意味します。

于 2014-10-20T18:45:51.733 に答える