For anyone who finds this, in Python 3 string and bytes are now different. ctypes needs a bytes instance in order to correctly pass the parameter as char*.

test_lib.get_val(b'Test1', byref(a)) will pass the full 'Test1' as a char* to the c function

test_lib.get_val('Test1', byref(a)) will not pass 'Test1' as a char*, from my little bit of testing it passes the first letter of the python str followed by a null charcter.

Answer from Keenan Kugler on Stack Overflow
🌐
Berton's Workshop
d0048.github.io › blog › 2017 › 10 › 11 › Pass-Strings-from-Python-to-C-CPP-libs
Pass Strings from Python to C/CPP libs | Berton's Workshop
October 12, 2017 - Non-specifically-encoded strings are usually stored as wide chars(wchar), where a string "test" in python basically looks like "t\0e\0s\0t\0". This will mess with any functions in C relying on \0 to find the end of a string(char*). Encoded string are stored in the specified codec. Then, to pass a string object as char* or wchar_t* into native libiaries:
Discussions

ctypes how to pass string from python to c++ function, and how to return string from c++ function to python - Stack Overflow
I want to call a c++ function from python, this c++ function takes char* as parameter, and return string. Below is my code. wrapper.cpp #include #include #include ... More on stackoverflow.com
🌐 stackoverflow.com
September 4, 2017
Passing byte string from Python to C - Stack Overflow
I am writing a python extension in C and I am trying to pass a bytes object to my function. Obviously the 's' token is for strings; I have tried 'O', 'N', and a few others with no luck. Is there a... More on stackoverflow.com
🌐 stackoverflow.com
How to pass Python string to C++ (extern C) function - Stack Overflow
8 ctypes how to pass string from python to c++ function, and how to return string from c++ function to python More on stackoverflow.com
🌐 stackoverflow.com
Issue with passing string from Python to C shared lib using ctypes - Stack Overflow
I tried to change c_char_p to c_wchar_p or c_char*5 or c_wchar*5 etc. Sometimes it can run without error, the first int parameter of the struct can be printed correctly, but not the second string pointer, the best I can get is just the first character 't' instead of the whole word "test". ... I don't know anything about sending data between C and Python... More on stackoverflow.com
🌐 stackoverflow.com
🌐
CopyProgramming
copyprogramming.com › howto › pass-python-str-to-c-function
Python: Transferring Python String to a C Function
June 11, 2023 - Based on my limited testing, test_lib.get_val('Test1', byref(a)) only passes the initial letter of the Python language str before a null character is added, and therefore it cannot pass as a char* for 'Test1'. ... The Python string is correctly adapted by ctypes to match the function that requires char* .
Top answer
1 of 1
12

This has nothing to do with ctypes; your C++ code is invalid in itself. You can't define an extern "C" function that returns a string.

In a quick test with a C++ program that uses the same library, it also prints garbage.

I also wrote a C program that defines something called string with the same layout as std::string just so I could compile it and see what happens; it also prints garbage, and then it segfaults in ~string.

So, it's not surprising that the Python program also prints garbage.

With a minor change, everything works:

extern "C"
const char *return_string(char* name){
    cout<<strlen(name)<<endl;
    cout<<name<<endl;
    static string s = "hello ";
    s += name;
    return s.c_str();
}

I get this output:

3
Tom
hello Tom
<ctypes.c_char_Array_4 object at 0x11011c7a0>

(Or, from the C++ version, the same thing but with "Tom" in the last line.)

Of course for obvious reasons this isn't a very good solution, but it shows that returning string is the problem.

Both g++-4.5 and clang-apple-4.0 warned me about exactly this problem when I tried to compile your C++ code (although g++-apple-4.2 didn't, unless I added an extra -W flag). When the compiler gives you a warning, that's often the answer to "why does my code do the wrong thing even though it compiles".

A few other things wrong with your code:

  • You don't make any use of anything from Python in your .cpp file. And in general, the whole point of using ctypes is so your C or C++ code doesn't have to know anything about Python; it's your Python code that knows about it. So, don't include or link.
  • It's generally a bad idea to take a non-const char* if you aren't planning to modify it. My C++ driver had to call it with const_cast<char*>(name.c_str()) instead of just name.c_str(). Also, this can prevent the compiler from noticing other things that you're doing.

Here's the C++ driver I mentioned above:

#include <iostream>
#include <string>
using namespace std;

extern "C" string return_string(char* name);

int main(int argc, char *argv[]) {
  string name("Tom");
  string s(return_string(const_cast<char *>(name.c_str())));
  cout << s << "\n";
  cout << name << "\n";
  return 0;
}

Also, if I play around with different optimization settings or reorganize the code a bit, in my C++ driver, sometimes your code actually works, sometimes it prints garbage, and sometimes it segfaults. My first guess would be that it depends where the ~string call gets inlined—but really, the details don't matter; the code shouldn't work, and it doesn't, so who cares why?

🌐
GitHub
gist.github.com › helinwang › 4f287a52efa4ab75424c01c65d77d939
Call go (or c) code from python with string as argument and string as return value · GitHub
Using c_char_p as argument, making a copy in go code when converting to go string. When using the first method without the copy, I don't know how python will do the memory management with the pointer passed into go. So the second method is preferred. The go function ...
🌐
Cython
cython.readthedocs.io › en › latest › src › tutorial › strings.html
Unicode and passing strings — Cython 3.3.0 documentation
To ease conversion between Python and C strings in simple cases, the module-level c_string_type and c_string_encoding directives can be used to implicitly insert these encoding/decoding steps. Cython supports four Python string types: bytes, str, unicode and basestring.
🌐
Python
docs.python.org › 3.4 › extending › extending.html
1. Extending Python with C or C++ — Python 3.4.10 documentation
July 16, 2019 - The arg argument must be a tuple object containing an argument list passed from Python to a C function. The format argument must be a format string, whose syntax is explained in Parsing arguments and building values in the Python/C API Reference Manual.
🌐
YouTube
youtube.com › hey delphi
C++ : ctypes how to pass string from python to c++ function, and how to return string from c++ funct - YouTube
C++ : ctypes how to pass string from python to c++ function, and how to return string from c++ function to pythonTo Access My Live Chat Page, On Google, Sear...
Published: May 5, 2023
Views: 141
Find elsewhere
🌐
Stack Overflow
stackoverflow.com › questions › 62358170 › how-to-pass-python-string-to-c-extern-c-function
How to pass Python string to C++ (extern C) function - Stack Overflow
In cpp if I pass string in isNEsixt function it will print whole string correctly and string_type is <class '__main__.c_char_p_Array_12'>, so I assume that I missing something in result row in Python code ... #include <string> #include <iostream> extern "C" { int isNExist (char* sequence) { std::cout << sequence << std::endl; return 0; } ... from ctypes import cdll, c_char_p, c_char, c_float, c_int,c_wchar_p,addressof, create_string_buffer,POINTER # connect to .so lib = cdll.LoadLibrary('mylib.so') # set data types of arguments of cpp function lib.isNExist.argtypes = [c_char_p] # set result data type lib.isNExist.restype = c_int # string I want to pass to the function s = "Hello world!".encode("UTF-8") # create buffer that will pass my string to cpp function buff = create_string_buffer(s) # passing buff to function result = lib.isNExist(buff)
🌐
Stack Overflow
stackoverflow.com › questions › 55037429 › passing-string-from-python-to-c-using-ctypes-only-the-first-character-is-sen › 55054353
passing string from python to c++ using ctypes - only the first character is sent - Stack Overflow
I am trying to send a multi-character string from Python to C++ using ctypes. However only the first character of each string is passed. This is the call in Python: ctypes.cdll.LoadLibrary(os.path.
🌐
Stack Overflow
stackoverflow.com › questions › 42073007 › ctypes-passing-string-as-argument-from-python-to-c
c++ - Ctypes: passing string as argument from Python to C - Stack Overflow
June 2, 2017 - But here is my python class: from ctypes import cdll, c_char_p clib = cdll.LoadLibrary('./libfoo.so') class Session(object): def __init__(self): self.obj = clib.tunnel_init() def start(self, user_input): clib.tunnel_start.restype = c_char_p clib.tunnel_start.argtypes = [c_char_p] a = c_char_p(user_input) result = clib.tunnel_start(self.obj, a) return str(result) ... Seems like my argument is treated like a string, not as a pointer.
Top answer
1 of 1
1
Table of Contants Introduction When working with C libraries in Python using the ctypes module, you may encounter functions that accept a char** argument. This typically represents a pointer to a pointer to a character, which can be used to pass strings or arrays of strings to C functions. This guide will show you how to pass a string from Python to such a function. Passing a String to a C Library Function Accepting char** 1. Import the ctypes Module First, make sure to import the ctypes module. import ctypes 2. Define the C Function For demonstration purposes, let’s assume you have a simple C function that takes a char** argument. Below is a simple example of such a function: // example.c #include void print_strings(char** strings, int count) { for (int i = 0; i < count; i++) { printf("%s\n", strings[i]); } } Compile this C code into a shared library (e.g., example.so on Linux or example.dll on Windows). 3. Load the Shared Library In your Python code, load the shared library using ctypes: # Load the shared library example = ctypes.CDLL('./example.so') # Adjust the path as necessary 4. Define the Argument Types Next, define the argument types for the C function. In this case, the function accepts a char** and an int: example.print_strings.argtypes = (ctypes.POINTER(ctypes.c_char_p), ctypes.c_int) 5. Prepare the String Data To pass a string (or an array of strings) to the C function, you need to create an array of c_char_p. Here's how you can do that: # Prepare a list of strings strings = [b"Hello", b"World", b"from ctypes"] # Create a ctypes array of c_char_p string_array_type = ctypes.c_char_p * len(strings) c_string_array = string_array_type(*strings) 6. Call the C Function Now you can call the C function, passing the array of strings and the count: # Call the C function example.print_strings(c_string_array, len(strings)) 7. Full Example Here’s the complete code to illustrate the entire process: import ctypes # Load the shared library example = ctypes.CDLL('./example.so') # Define the argument types for the C function example.print_strings.argtypes = (ctypes.POINTER(ctypes.c_char_p), ctypes.c_int) # Prepare a list of strings strings = [b"Hello", b"World", b"from ctypes"] # Create a ctypes array of c_char_p string_array_type = ctypes.c_char_p * len(strings) c_string_array = string_array_type(*strings) # Call the C function example.print_strings(c_string_array, len(strings)) Conclusion Passing a string (or an array of strings) to a C library function that accepts char** can be easily accomplished in Python using the ctypes module. By defining the function's argument types, preparing your string data, and calling the function with the correct arguments, you can seamlessly interface with C libraries from Python. This capability allows for powerful integrations and can help leverage existing C code within Python applications.
🌐
GeeksforGeeks
geeksforgeeks.org › python › unicode-strings-passing-to-c-libraries
Unicode Strings Passing to C Libraries - GeeksforGeeks
April 2, 2019 - Therefore, the main challenge is to convert the Python string into a form that can be more easily understood by C libraries. To illustrate the solution - given below are two C functions that operate on string data and output it for debugging and experimentation. Code #1 : Uses bytes provided in the form char *, int
Top answer
1 of 2
8

There are a number of problems:

  1. Define .argtypes for your functions. It will catch errors passing incorrect parameters. Add the line below and note it is plural and is a tuple of argument types. The comma makes a 1-tuple:

python_p_printme.argtypes = c_char_p,

  1. Once you make that change, you'll get an error because this code:

    c_sends = pointer(c_char_p(CHAR.encode('utf-8')

is actually sending a C char** (a pointer to a c_char_p). Once you've set the argtypes properly, you can just call the function with a byte string and it will work. Your function becomes:

def printmeP(CHAR):
    print("In Print function")
    print(CHAR)
    python_p_printme(CHAR.encode())
    print("DONE function - Python")
  1. There is one more subtle problem. While the program may appear to work at this point Python strings are immutable so if the function being called requires a mutable string, you must allocate a mutable buffer using either create_unicode_buffer (for c_wchar_p) or create_string_buffer (for c_char_p); otherwise, the strcat in your C code is going to corrupt the Python string.

Here's a full example:

test.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// For Windows compatibility
#ifdef _WIN32
#   define API __declspec(dllexport)
#else
#   define API
#endif

// For C++ compiler compatibility
#ifdef __cplusplus
extern "C" {
#endif

API void alter_me(char* param, size_t length) {
    // truncates if additional info exceeds length
    strncat_s(param, length, " adding some info", length - 1);
}

#ifdef __cplusplus
}
#endif

test.py

from ctypes import *

lib = CDLL('./test')
alter_me = lib.alter_me
alter_me.argtypes = c_char_p,c_size_t
alter_me.restype = None

data = create_string_buffer(b'test',size=10)
alter_me(data,sizeof(data))
print(data.value)

data = create_string_buffer(b'test',size=50)
alter_me(data,sizeof(data))
print(data.value)

Output:

b'test addi'
b'test adding some info'

Note you do not need to use create_string_buffer if the C function does not alter the buffer, such as if the C parameter is const char*. Then you could just call printme(b'test string').

2 of 2
2

You could use create_string_buffer.

The documentation can be found here: https://docs.python.org/3/library/ctypes.html#ctypes.create_string_buffer

ctypes.create_string_buffer(init_or_size, size=None)

This function creates a mutable character buffer. The returned object is a ctypes array of c_char.

init_or_size must be an integer which specifies the size of the array, or a bytes object which will be used to initialize the array items.

With buf.value.decode("utf-8") you can convert the buffer back to a UTF-8 python string.

A small example with your C code library might look like this:

from ctypes import *

mylib_lib = cdll.LoadLibrary("<your-lib>")
mylib_lib.printme.argtypes = c_char_p,

buf = create_string_buffer(128)
buf.value = b'Hello World'
mylib_lib.printme(buf)
print("print on python side:", buf.value.decode("utf-8"))

It would output:

Start c Function!
Hello World
...
print on python side: Hello World!

on the console.