Why is printf() giving a strange output in python?
Question:
I tried to use the C-function printf()
in the python command line on Linux. To make that work, I imported ctypes
. My problem is: If I create an object of CDLL
to use the printf()
-function in a loop, I get a really weird output:
>>> import ctypes
>>> libc = ctypes.CDLL("libc.so.6")
>>> for i in range(10):
... libc.printf("%d", i)
...
01
11
21
31
41
51
61
71
81
91
>>>
However, when I call this loop inside a function, it works as expected:
>>> import ctypes
>>> libc = ctypes.CDLL("libc.so.6")
>>> def pr():
... for i in range(10):
... libc.printf("%d", i)
... libc.printf("n")
...
>>> pr()
0123456789
>>>
I can’t guess what causes this behavior …
I’m using Python 2.7.6 on Linux if it matters.
EDIT:
Python version / operating system has no influence to this. See PM 2Ring’s answer below for details. On Windows you only have to change the initialization of libc
to libc = ctypes.CDLL("msvcrt.dll")
where .dll
is optional. Another way to get the correct output than calling a function would be storing the return value of printf()
in a variable:
>>> import ctypes
>>> libc = ctypes.CDLL("libc.so.6") # "mscvrt.dll" on windows
>>> for i in range(10):
... r = libc.printf("%d", i)
...
0123456789>>>
I still prefer the function because you can add a concluding linebreak easier.
Answers:
Those extra '1'
s at the end of each number are the return value from printf
, which returns the number of chars that it prints. The return value of a function called in the interactive interpreter is automatically printed (unless it’s None
).
In fact, the interactive interpreter prints any non-None
expression that isn’t assigned. And of course it adds a newline to those expressions, which explains why the output in your first code block is on separate lines.
Your pr
function doesn’t have a return statement, so it returns None
, and thus no extra stuff gets printed.
While PM 2Ring has answered the question quite well, I think it’s worth pointing out that printf’s behaviour, or something very close, is available as a python built-in, so it’s really quite strange that you’d be using the C library version, unless you’re using it to learn how to use ctypes
, in which case carry on.
But on the other hand, it’s strange to want to use ctypes
when you haven’t used enough python to know how the REPL works… at the risk of sounding arrogant, as someone with 10 years of python experience, I’ve never actually had to use ctypes
yet.
There are two built-in options for string formatting in python:
print("%d" % (i,))
which is the old style, and very similar to printf, and
print("{:d}".format(i))
which is new to python 3, and is somewhat more powerful. There are questions addressing the differences on this site. Both of the above lines will output identically to libc.printf("%dn", i)
. It’s also possible to print without the newline.
The CPython implementation of “%” string formatting actually uses sprintf under the hood.
I tried to use the C-function printf()
in the python command line on Linux. To make that work, I imported ctypes
. My problem is: If I create an object of CDLL
to use the printf()
-function in a loop, I get a really weird output:
>>> import ctypes
>>> libc = ctypes.CDLL("libc.so.6")
>>> for i in range(10):
... libc.printf("%d", i)
...
01
11
21
31
41
51
61
71
81
91
>>>
However, when I call this loop inside a function, it works as expected:
>>> import ctypes
>>> libc = ctypes.CDLL("libc.so.6")
>>> def pr():
... for i in range(10):
... libc.printf("%d", i)
... libc.printf("n")
...
>>> pr()
0123456789
>>>
I can’t guess what causes this behavior …
I’m using Python 2.7.6 on Linux if it matters.
EDIT:
Python version / operating system has no influence to this. See PM 2Ring’s answer below for details. On Windows you only have to change the initialization of libc
to libc = ctypes.CDLL("msvcrt.dll")
where .dll
is optional. Another way to get the correct output than calling a function would be storing the return value of printf()
in a variable:
>>> import ctypes
>>> libc = ctypes.CDLL("libc.so.6") # "mscvrt.dll" on windows
>>> for i in range(10):
... r = libc.printf("%d", i)
...
0123456789>>>
I still prefer the function because you can add a concluding linebreak easier.
Those extra '1'
s at the end of each number are the return value from printf
, which returns the number of chars that it prints. The return value of a function called in the interactive interpreter is automatically printed (unless it’s None
).
In fact, the interactive interpreter prints any non-None
expression that isn’t assigned. And of course it adds a newline to those expressions, which explains why the output in your first code block is on separate lines.
Your pr
function doesn’t have a return statement, so it returns None
, and thus no extra stuff gets printed.
While PM 2Ring has answered the question quite well, I think it’s worth pointing out that printf’s behaviour, or something very close, is available as a python built-in, so it’s really quite strange that you’d be using the C library version, unless you’re using it to learn how to use ctypes
, in which case carry on.
But on the other hand, it’s strange to want to use ctypes
when you haven’t used enough python to know how the REPL works… at the risk of sounding arrogant, as someone with 10 years of python experience, I’ve never actually had to use ctypes
yet.
There are two built-in options for string formatting in python:
print("%d" % (i,))
which is the old style, and very similar to printf, and
print("{:d}".format(i))
which is new to python 3, and is somewhat more powerful. There are questions addressing the differences on this site. Both of the above lines will output identically to libc.printf("%dn", i)
. It’s also possible to print without the newline.
The CPython implementation of “%” string formatting actually uses sprintf under the hood.