Eryk Sun added the comment:

> from ctypes import *
> msvcrt = cdll.msvcrt
> message_string = "Hello World!\n"
> msvcrt.printf("Testing: %s", message_string)

Avoid using libraries as attributes of cdll and windll. They get cached, and in 
turn they cache function pointers. Thus all modules contend for cdll and windll 
function prototype definitions (i.e. argtypes, restype, errcheck), and the last 
one to modify the definition wins. Even if you're not setting prototypes (in 
which case you must really like segfaults, data corruption, and 
difficult-to-diagnose errors), your code will still be at the mercy of 
whichever module does set them. Instead use the following:

    msvcrt = ctypes.CDLL('msvcrt', use_errno=True)
    msvcrt.printf.argtypes = (ctypes.c_char_p,)

CDLL uses the cdecl calling convention. This convention uses callee stack 
cleanup, so we allow passing a variable number of arguments even though the 
above argtypes definition only checks the first argument.

Examples

You'll get an exception if the first argument isn't bytes:

    >>> msvcrt.printf("spam and %d %s\n", 42, "eggs")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ctypes.ArgumentError: argument 1: <class 'TypeError'>: wrong type

Since we're not checking additional arguments, you might accidentally pass a 
wide-character string. In that case of course the output will be wrong:

    >>> msvcrt.printf(b"spam and %d %s\n", 42, "eggs")
    spam and 42 e
    14

Here we get it right:

    >>> msvcrt.printf(b"spam and %d %s\n", 42, b"eggs")
    spam and 42 eggs
    17

Or maybe you need to print a wide-character string, i.e. "%ls" or "%S":

    >>> msvcrt.printf(b"spam and %d %ls\n", 42, "eggs")
    spam and 42 eggs
    17

or

    >>> msvcrt.printf(b"spam and %d %S\n", 42, "eggs")
    spam and 42 eggs
    17

The "%s" and "%S" convention in MSVC predates standard C. In Microsoft's 
printf, "%s" expects a char pointer and "%S" expects a wchar_t pointer, but in 
their wprintf it's the other way around. In standard C "%s" and "%ls" are 
always a char string and a wchar_t string, respectively. MSVC also supports the 
standard "%ls" for wide-character strings, but its non-standard use of "%s" 
requires the introduction of a non-standard "%hs" for char strings.

----------
nosy: +eryksun

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue29131>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to