2016-05-27 11 views
2

Grey Hat Pythonの例の1つに従っていますが、Python 2.7ではうまく動作しますが、Python 3.5では結果が切り捨てられます。Python 3.5 ctypes libc printf()は文字列の最初のバイトのみを出力します。Windows 7/10

from ctypes import * 

msvcrt = cdll.msvcrt 
message_string = "Hello World!\n" 
msvcrt.printf("Testing: %s\n", message_string) 

上記のコードの出力は、文字がTであることがわかります。

enter image description here

基づき1本1と同様のいくつかの他の記事、最後の行にbを追加することができますが、その後message_stringが切り捨てられます。

from ctypes import * 

msvcrt = cdll.msvcrt 
message_string = "Hello World!\n" 
msvcrt.printf(b"Testing: %s\n", message_string) 

enter image description here

は、どのように私はそれがWindows 7または10でPython 3.5を使用して、message_string変数に保存されている文字列全体を印刷するのですか?

+0

文字コードを関数で扱える文字セットにエンコードしようとしましたか? –

+0

'msvcrt.printf.argtypes =(ctypes.c_char_p、)'を設定して、最初の引数の型検査を強制します。このバリデーショナル関数の追加の引数はフォーマット文字列に依存するので、それらをチェックしないままにしておきますが、ここでは常識を使います。 Python 3はUnicode文字列を使用しているので、前のコメントからもわかるように、文字列を 'bytes'としてエンコードする必要があります。また、 'cdll'の使用は避けてください。これは、関数ポインタをキャッシュするモジュールをグローバルにキャッシュするため、ライブラリとスクリプトのプロトタイプ競合(つまり、' restype'、 'argtypes'、' errcheck')につながります。 'msvcrt = ctypes.CDLL( 'msvcrt')'を使用してください。 – eryksun

+0

また、グレイ・ハット・パイソン(Grey Hat Python)を塩の塊で取る。この本のコードに基づいた数多くの例を見てきましたが、ポインタやモジュールハンドルに依存する多くのコードが64ビットWindowsで破損するなど、プロトタイプの設定を無差別に無視するコードで満たされていることを十分に知っています。 'WinDLL'の' use_last_error'パラメータを使用して 'ctypes.get_last_error'と' ctypes.set_last_error'(スレッドローカルストレージに基づいて安全な 'GetLastError'と' SetLastError')を有効にするなど、適切なエラーチェックを行います。 – eryksun

答えて

4

は、それが動作するようになった%シンボルの代わりにカンマを持っています!変数宣言にbを追加する必要があります。このような小さなディテールすぎ...以下の調整のコードを参照してください:

のPython 3.5ワット/ Windows 7の64ビット版、&のWindows 10の64ビット

enter image description here

3.4のPython/Wグレーハットでテスト
from ctypes import * 

msvcrt = CDLL('msvcrt') 
message_string = b"Hello World!\n" 
msvcrt.printf(b"Testing: %s\n", message_string) 

をPython - chapter1-printf.py - 例

+1

'b'接頭辞の小さな細部は、'バイト 'リテラルであり、ASCIIバイト文字列' b "Hello World!\ n" 'とUTF-16LEでエンコードされた文字列(Windowsの場合)' ' x00 \ x00 \ x00o \ x00 \ x00 \ x00o \ x00r \ x00l \ x00d \ x00!\ x00 \ n \ x00 "のように入力します。 – eryksun

+1

あなたがインポートしたライブラリでも 'cdll.msvcrt.printf.argtypes =(c_char_p、c_char_p、c_int)'のようなものが定義されていれば、 'printf'には3つの引数が必要なため、コードが再度破壊されます。 'cdll'と' windll'ローダーは悪い考えでした。これを 'msvcrt = CDLL( 'msvcrt')'に変更して、 'msvcrt'へのプライベートリファレンスを取得します。 – eryksun

+0

追加の洞察@eryksunありがとう。私は実際にあなたが言及した両方の点の違いが何であるか疑問に思っていました。 – Chris

0

コマンドはmsvcrt.printf("Testing: %s\n" % message_string)する必要があります - あなたは

+2

この回答は二重に間違っています。 'bytes'(つまり' ctypes.c_char_p')が必要な 'printf'にUnicode文字列を渡しています。そしてPythonに文字列の書式設定をさせることで、Cのvariadicの' printf'関数全体が失われてしまいます。 – eryksun

関連する問題