5

I want to print a C string using the Python print statement. The array vendorName contains the ASCIIZ C string A ANTHONY & SONS INC. My motivation is to convert the C string to a Python string such that I can use all of the Python string methods.

I have a struct:

class _vendrRecord(Structure):
    _pack_ = 1                                            # pack the struct
    _fields_ = [
        ("vendorName"            ,c_ubyte *(40 + 1)),
        ("ytdPayments"           ,c_ulong),
        ]

I want to print the string "vendorName" which is ASCIIZ.

I can print it using printf like this:

printf(b"%s\n", vendrRecord.vendorName)

I have tried this print(vendrRecord.vendorName) but it just prints the address. Based on information from Jamie Nicholl-Shelley, I tried print(cast(vendrRecord.vendorName,c_char_p).value) but that gives b'A ANTHONY & SONS INC'. I want simply A ANTHONY & SONS INC

Note that print(vendrRecord.ytdPayments) prints correctly.

2
  • Can't you access the string with vendrRecord.vendorName.content? I'm not so much into ctypes though. Commented Jan 9, 2016 at 21:38
  • vendrRecord.vendorName.content gives AttributeError: 'c_ubyte_Array_41' object has no attribute 'content' Commented Jan 10, 2016 at 13:08

2 Answers 2

4

It looks like you've figured out most of it and are just confused about string encoding. You've managed to get to a bytes object:

>>> v.vendorName
<__main__.c_ubyte_Array_41 object at 0xb0994a04>
>>> cast(v.vendorName, c_char_p)
c_char_p(176882328)
>>> cast(v.vendorName, c_char_p).value
b'A ANTHONY & SONS INC'

The bytes object is what it sounds like, just a sequence of bytes -- it's only as a convenience for the user that it's shown in a stringlike way. Unlike a string, each component is an integer:

>>> cast(v.vendorName, c_char_p).value[7]
78

But since we know that we're using ascii, we can decode this bytes object into a Python string, and then use all of the usual methods on it:

>>> s = cast(v.vendorName, c_char_p).value.decode("ascii")
>>> s
'A ANTHONY & SONS INC'
>>> type(s)
<class 'str'>
>>> s.lower()
'a anthony & sons inc'
Sign up to request clarification or add additional context in comments.

2 Comments

Perfect! This does exactly what I want. It is interesting that your Python prints s.lower() with quotes but mine does not. I'm using the latest 32 bit version.
@Eddy: I didn't print anything. Since I was working at the console, it showed me the repr. If I'd done print(s.lower()), there would have been no quotes.
1

You are printing the address as that is what you have asked the code to do. You have told it that it is a string type, but not declared it as a string in the function, instead use a pointer to the data at the address

Compared to print(), which figures this out for you as it a c++ based function

2 Comments

That information got me closer but still not all the way. print(cast(vendrRecord.vendorName,c_char_p)) gives c_char_p(b'A ANTHONY & SONS INC'). How do I dereference it such that it is now a Python string? So I tried print(cast(vendrRecord.vendorName,c_char_p).value) but that gives b'A ANTHONY & SONS INC' (note the b).
Sorry I don't do much Python now days. I imagine it's an output type identifier that's used to link with the python compiler.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.