Inconsistent c_char_p behavior between returning vs pointer assignment
Consider the following C functions:
void AssignPointer(char **p) {
*p = "Test1";
}
char* Return() {
return "Test2";
}
Now consider the following code in Python:
import ctypes
lib = CDLL('LibraryPathHere')
lib.AssignPointer.restype = None
lib.AssignPointer.argtypes = (ctypes.POINTER(ctypes.c_char_p),)
lib.Return.restype = ctypes.c_char_p
lib.Return.argtypes = None
def to_python_string(c_str : ctypes.c_char_p) -> str:
return c_str.value.decode('ascii')
Now the following works:
c_str = ctypes.c_char_p()
lib.AssignPointer(ctypes.byref(c_str))
print(to_python_string(c_str))
However the following gives AttributeError: 'bytes' object has no attribute 'value'
:
c_str = lib.Return()
print(to_python_string(c_str))
In the first case the debugger shows c_str
as c_char_p(ADDRESS_HERE)
. In the second case the debugger shows c_str
as b'Test2'
.
So is this a bug in Python/ctypes or am I doing something wrong?
python c string interop ctypes
add a comment |
Consider the following C functions:
void AssignPointer(char **p) {
*p = "Test1";
}
char* Return() {
return "Test2";
}
Now consider the following code in Python:
import ctypes
lib = CDLL('LibraryPathHere')
lib.AssignPointer.restype = None
lib.AssignPointer.argtypes = (ctypes.POINTER(ctypes.c_char_p),)
lib.Return.restype = ctypes.c_char_p
lib.Return.argtypes = None
def to_python_string(c_str : ctypes.c_char_p) -> str:
return c_str.value.decode('ascii')
Now the following works:
c_str = ctypes.c_char_p()
lib.AssignPointer(ctypes.byref(c_str))
print(to_python_string(c_str))
However the following gives AttributeError: 'bytes' object has no attribute 'value'
:
c_str = lib.Return()
print(to_python_string(c_str))
In the first case the debugger shows c_str
as c_char_p(ADDRESS_HERE)
. In the second case the debugger shows c_str
as b'Test2'
.
So is this a bug in Python/ctypes or am I doing something wrong?
python c string interop ctypes
add a comment |
Consider the following C functions:
void AssignPointer(char **p) {
*p = "Test1";
}
char* Return() {
return "Test2";
}
Now consider the following code in Python:
import ctypes
lib = CDLL('LibraryPathHere')
lib.AssignPointer.restype = None
lib.AssignPointer.argtypes = (ctypes.POINTER(ctypes.c_char_p),)
lib.Return.restype = ctypes.c_char_p
lib.Return.argtypes = None
def to_python_string(c_str : ctypes.c_char_p) -> str:
return c_str.value.decode('ascii')
Now the following works:
c_str = ctypes.c_char_p()
lib.AssignPointer(ctypes.byref(c_str))
print(to_python_string(c_str))
However the following gives AttributeError: 'bytes' object has no attribute 'value'
:
c_str = lib.Return()
print(to_python_string(c_str))
In the first case the debugger shows c_str
as c_char_p(ADDRESS_HERE)
. In the second case the debugger shows c_str
as b'Test2'
.
So is this a bug in Python/ctypes or am I doing something wrong?
python c string interop ctypes
Consider the following C functions:
void AssignPointer(char **p) {
*p = "Test1";
}
char* Return() {
return "Test2";
}
Now consider the following code in Python:
import ctypes
lib = CDLL('LibraryPathHere')
lib.AssignPointer.restype = None
lib.AssignPointer.argtypes = (ctypes.POINTER(ctypes.c_char_p),)
lib.Return.restype = ctypes.c_char_p
lib.Return.argtypes = None
def to_python_string(c_str : ctypes.c_char_p) -> str:
return c_str.value.decode('ascii')
Now the following works:
c_str = ctypes.c_char_p()
lib.AssignPointer(ctypes.byref(c_str))
print(to_python_string(c_str))
However the following gives AttributeError: 'bytes' object has no attribute 'value'
:
c_str = lib.Return()
print(to_python_string(c_str))
In the first case the debugger shows c_str
as c_char_p(ADDRESS_HERE)
. In the second case the debugger shows c_str
as b'Test2'
.
So is this a bug in Python/ctypes or am I doing something wrong?
python c string interop ctypes
python c string interop ctypes
edited Jan 1 at 22:34
Serge Rogatch
asked Jan 1 at 22:28


Serge RogatchSerge Rogatch
6,42923468
6,42923468
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
ctypes automatically converts c_char_p
return values to bytes objects.
Fundamental data types, when returned as foreign function call results, or, for example, by retrieving structure field members or array items, are transparently converted to native Python types. In other words, if a foreign function has a restype of c_char_p, you will always receive a Python bytes object, not a c_char_p instance.
If you want the actual pointer value, use ctypes.POINTER(ctypes.c_char)
as the restype
.
If this functions as designed, could you elaborate on how to workaround this?
– Serge Rogatch
Jan 1 at 22:35
@SergeRogatch: Answer expanded.
– user2357112
Jan 1 at 22:39
If I changerestype
toctypes.POINTER(ctypes.c_char_p)
, I get error:AttributeError: 'LP_c_char_p' object has no attribute 'value'
– Serge Rogatch
Jan 1 at 22:50
@SergeRogatch: First, it'sctypes.POINTER(ctypes.c_char)
, notctypes.POINTER(ctypes.c_char_p)
. Second, you're going to need more adjustment than just swapping out the restype.c_char_p
is a "pseudo-primitive" type that doesn't behave like normal pointers. You're going to have to do pointer handling yourself, or cast back to c_char_p.
– user2357112
Jan 1 at 22:53
add a comment |
Finally here is a workaround for this problem:
To avoid automatic conversions of c_char_p
to bytes
, set C function's restype
as c_void_p
:
lib.Return.restype = ctypes.c_void_p
Then cast
to c_char_p
before passing to a function that expects c_char_p
as the common case:
void_ptr = lib.Return()
c_str = ctypes.cast(void_ptr, ctypes.c_char_p)
print(to_python_string(c_str))
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53999442%2finconsistent-c-char-p-behavior-between-returning-vs-pointer-assignment%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
ctypes automatically converts c_char_p
return values to bytes objects.
Fundamental data types, when returned as foreign function call results, or, for example, by retrieving structure field members or array items, are transparently converted to native Python types. In other words, if a foreign function has a restype of c_char_p, you will always receive a Python bytes object, not a c_char_p instance.
If you want the actual pointer value, use ctypes.POINTER(ctypes.c_char)
as the restype
.
If this functions as designed, could you elaborate on how to workaround this?
– Serge Rogatch
Jan 1 at 22:35
@SergeRogatch: Answer expanded.
– user2357112
Jan 1 at 22:39
If I changerestype
toctypes.POINTER(ctypes.c_char_p)
, I get error:AttributeError: 'LP_c_char_p' object has no attribute 'value'
– Serge Rogatch
Jan 1 at 22:50
@SergeRogatch: First, it'sctypes.POINTER(ctypes.c_char)
, notctypes.POINTER(ctypes.c_char_p)
. Second, you're going to need more adjustment than just swapping out the restype.c_char_p
is a "pseudo-primitive" type that doesn't behave like normal pointers. You're going to have to do pointer handling yourself, or cast back to c_char_p.
– user2357112
Jan 1 at 22:53
add a comment |
ctypes automatically converts c_char_p
return values to bytes objects.
Fundamental data types, when returned as foreign function call results, or, for example, by retrieving structure field members or array items, are transparently converted to native Python types. In other words, if a foreign function has a restype of c_char_p, you will always receive a Python bytes object, not a c_char_p instance.
If you want the actual pointer value, use ctypes.POINTER(ctypes.c_char)
as the restype
.
If this functions as designed, could you elaborate on how to workaround this?
– Serge Rogatch
Jan 1 at 22:35
@SergeRogatch: Answer expanded.
– user2357112
Jan 1 at 22:39
If I changerestype
toctypes.POINTER(ctypes.c_char_p)
, I get error:AttributeError: 'LP_c_char_p' object has no attribute 'value'
– Serge Rogatch
Jan 1 at 22:50
@SergeRogatch: First, it'sctypes.POINTER(ctypes.c_char)
, notctypes.POINTER(ctypes.c_char_p)
. Second, you're going to need more adjustment than just swapping out the restype.c_char_p
is a "pseudo-primitive" type that doesn't behave like normal pointers. You're going to have to do pointer handling yourself, or cast back to c_char_p.
– user2357112
Jan 1 at 22:53
add a comment |
ctypes automatically converts c_char_p
return values to bytes objects.
Fundamental data types, when returned as foreign function call results, or, for example, by retrieving structure field members or array items, are transparently converted to native Python types. In other words, if a foreign function has a restype of c_char_p, you will always receive a Python bytes object, not a c_char_p instance.
If you want the actual pointer value, use ctypes.POINTER(ctypes.c_char)
as the restype
.
ctypes automatically converts c_char_p
return values to bytes objects.
Fundamental data types, when returned as foreign function call results, or, for example, by retrieving structure field members or array items, are transparently converted to native Python types. In other words, if a foreign function has a restype of c_char_p, you will always receive a Python bytes object, not a c_char_p instance.
If you want the actual pointer value, use ctypes.POINTER(ctypes.c_char)
as the restype
.
edited Jan 1 at 22:38
answered Jan 1 at 22:34
user2357112user2357112
156k12170264
156k12170264
If this functions as designed, could you elaborate on how to workaround this?
– Serge Rogatch
Jan 1 at 22:35
@SergeRogatch: Answer expanded.
– user2357112
Jan 1 at 22:39
If I changerestype
toctypes.POINTER(ctypes.c_char_p)
, I get error:AttributeError: 'LP_c_char_p' object has no attribute 'value'
– Serge Rogatch
Jan 1 at 22:50
@SergeRogatch: First, it'sctypes.POINTER(ctypes.c_char)
, notctypes.POINTER(ctypes.c_char_p)
. Second, you're going to need more adjustment than just swapping out the restype.c_char_p
is a "pseudo-primitive" type that doesn't behave like normal pointers. You're going to have to do pointer handling yourself, or cast back to c_char_p.
– user2357112
Jan 1 at 22:53
add a comment |
If this functions as designed, could you elaborate on how to workaround this?
– Serge Rogatch
Jan 1 at 22:35
@SergeRogatch: Answer expanded.
– user2357112
Jan 1 at 22:39
If I changerestype
toctypes.POINTER(ctypes.c_char_p)
, I get error:AttributeError: 'LP_c_char_p' object has no attribute 'value'
– Serge Rogatch
Jan 1 at 22:50
@SergeRogatch: First, it'sctypes.POINTER(ctypes.c_char)
, notctypes.POINTER(ctypes.c_char_p)
. Second, you're going to need more adjustment than just swapping out the restype.c_char_p
is a "pseudo-primitive" type that doesn't behave like normal pointers. You're going to have to do pointer handling yourself, or cast back to c_char_p.
– user2357112
Jan 1 at 22:53
If this functions as designed, could you elaborate on how to workaround this?
– Serge Rogatch
Jan 1 at 22:35
If this functions as designed, could you elaborate on how to workaround this?
– Serge Rogatch
Jan 1 at 22:35
@SergeRogatch: Answer expanded.
– user2357112
Jan 1 at 22:39
@SergeRogatch: Answer expanded.
– user2357112
Jan 1 at 22:39
If I change
restype
to ctypes.POINTER(ctypes.c_char_p)
, I get error: AttributeError: 'LP_c_char_p' object has no attribute 'value'
– Serge Rogatch
Jan 1 at 22:50
If I change
restype
to ctypes.POINTER(ctypes.c_char_p)
, I get error: AttributeError: 'LP_c_char_p' object has no attribute 'value'
– Serge Rogatch
Jan 1 at 22:50
@SergeRogatch: First, it's
ctypes.POINTER(ctypes.c_char)
, not ctypes.POINTER(ctypes.c_char_p)
. Second, you're going to need more adjustment than just swapping out the restype. c_char_p
is a "pseudo-primitive" type that doesn't behave like normal pointers. You're going to have to do pointer handling yourself, or cast back to c_char_p.– user2357112
Jan 1 at 22:53
@SergeRogatch: First, it's
ctypes.POINTER(ctypes.c_char)
, not ctypes.POINTER(ctypes.c_char_p)
. Second, you're going to need more adjustment than just swapping out the restype. c_char_p
is a "pseudo-primitive" type that doesn't behave like normal pointers. You're going to have to do pointer handling yourself, or cast back to c_char_p.– user2357112
Jan 1 at 22:53
add a comment |
Finally here is a workaround for this problem:
To avoid automatic conversions of c_char_p
to bytes
, set C function's restype
as c_void_p
:
lib.Return.restype = ctypes.c_void_p
Then cast
to c_char_p
before passing to a function that expects c_char_p
as the common case:
void_ptr = lib.Return()
c_str = ctypes.cast(void_ptr, ctypes.c_char_p)
print(to_python_string(c_str))
add a comment |
Finally here is a workaround for this problem:
To avoid automatic conversions of c_char_p
to bytes
, set C function's restype
as c_void_p
:
lib.Return.restype = ctypes.c_void_p
Then cast
to c_char_p
before passing to a function that expects c_char_p
as the common case:
void_ptr = lib.Return()
c_str = ctypes.cast(void_ptr, ctypes.c_char_p)
print(to_python_string(c_str))
add a comment |
Finally here is a workaround for this problem:
To avoid automatic conversions of c_char_p
to bytes
, set C function's restype
as c_void_p
:
lib.Return.restype = ctypes.c_void_p
Then cast
to c_char_p
before passing to a function that expects c_char_p
as the common case:
void_ptr = lib.Return()
c_str = ctypes.cast(void_ptr, ctypes.c_char_p)
print(to_python_string(c_str))
Finally here is a workaround for this problem:
To avoid automatic conversions of c_char_p
to bytes
, set C function's restype
as c_void_p
:
lib.Return.restype = ctypes.c_void_p
Then cast
to c_char_p
before passing to a function that expects c_char_p
as the common case:
void_ptr = lib.Return()
c_str = ctypes.cast(void_ptr, ctypes.c_char_p)
print(to_python_string(c_str))
answered Jan 1 at 23:09


Serge RogatchSerge Rogatch
6,42923468
6,42923468
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53999442%2finconsistent-c-char-p-behavior-between-returning-vs-pointer-assignment%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown