-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve compatibility between Cstring and Ptr. #14024
Changes from 3 commits
7e28d30
04d57fe
66f34ba
40f2d85
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -80,36 +80,38 @@ is that a 1-tuple must be written with a trailing comma. For | |
example, to call the ``getenv`` function to get a pointer to the value | ||
of an environment variable, one makes a call like this:: | ||
|
||
julia> path = ccall((:getenv, "libc"), Ptr{UInt8}, (Ptr{UInt8},), "SHELL") | ||
Ptr{UInt8} @0x00007fff5fbffc45 | ||
julia> path = ccall((:getenv, "libc"), Cstring, (Cstring,), "SHELL") | ||
Cstring(@0x00007fff5fbffc45) | ||
|
||
julia> bytestring(path) | ||
"/bin/bash" | ||
|
||
Note that the argument type tuple must be written as ``(Ptr{UInt8},)``, | ||
rather than ``(Ptr{UInt8})``. This is because ``(Ptr{UInt8})`` is just | ||
the expression ``Ptr{UInt8}`` surrounded by parentheses, rather than | ||
a 1-tuple containing ``Ptr{UInt8}``:: | ||
Note that the argument type tuple must be written as ``(Cstring,)``, | ||
rather than ``(Cstring)``. This is because ``(Cstring)`` is just | ||
the expression ``Cstring`` surrounded by parentheses, rather than | ||
a 1-tuple containing ``Cstring``: | ||
|
||
julia> (Ptr{UInt8}) | ||
Ptr{UInt8} | ||
.. doctest:: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. guess these could be doctests? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK. Do I need to do anything after converting the block to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh strange, maybe it's not a big enough deal to be worth worrying about then There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My mistake, I didn't realize |
||
|
||
julia> (Ptr{UInt8},) | ||
(Ptr{UInt8},) | ||
julia> (Cstring) | ||
Cstring | ||
|
||
julia> (Cstring,) | ||
(Cstring,) | ||
|
||
In practice, especially when providing reusable functionality, one | ||
generally wraps ``ccall`` uses in Julia functions that set up arguments | ||
and then check for errors in whatever manner the C or Fortran function | ||
indicates them, propagating to the Julia caller as exceptions. This is | ||
especially important since C and Fortran APIs are notoriously | ||
inconsistent about how they indicate error conditions. For example, the | ||
``getenv`` C library function is wrapped in the following Julia function | ||
in | ||
``getenv`` C library function is wrapped in the following Julia function, | ||
which is a simplified version of the actual definition from | ||
`env.jl <https://github.com/JuliaLang/julia/blob/master/base/env.jl>`_:: | ||
|
||
function getenv(var::AbstractString) | ||
val = ccall((:getenv, "libc"), | ||
Ptr{UInt8}, (Ptr{UInt8},), var) | ||
Cstring, (Cstring,), var) | ||
if val == C_NULL | ||
error("getenv: undefined variable: ", var) | ||
end | ||
|
@@ -148,6 +150,10 @@ C libraries to use this pattern of requiring the caller to allocate | |
memory to be passed to the callee and filled in. Allocation of memory | ||
from Julia like this is generally accomplished by creating an | ||
uninitialized array and passing a pointer to its data to the C function. | ||
This is why we don't use the ``Cstring`` type here: as the array is | ||
uninitialized, it could contain NUL bytes. Converting to a ``Cstring`` as | ||
part of the ``ccall`` checks for contained NUL bytes and could therefore | ||
throw a conversion error. | ||
|
||
Creating C-Compatible Julia Function Pointers | ||
--------------------------------------------- | ||
|
@@ -421,6 +427,8 @@ error if the Julia string contains any embedded NUL characters (which would caus | |
truncated if the C routine treats NUL as the terminator). If you are passing a ``char*`` to a C routine that | ||
does not assume NUL termination (e.g. because you pass an explicit string length), or if you know for certain that | ||
your Julia string does not contain NUL and want to skip the check, you can use ``Ptr{UInt8}`` as the argument type. | ||
``Cstring`` can also be used as the `ccall` return type, but in that case it obviously does not introduce any extra | ||
checks and is only meant to improve readability of the call. | ||
|
||
**System-dependent:** | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is ther any problem with converting non-NULL
Ptr{Void}
toCstring
? Also, isn't this always returningCstring
even when called withCwstring
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then how would
bytestring(Cstring)
behave? Currently, it only checks forptr != C_NULL
, relying on the fact thatptr
points to a NULL-terminated array of chars. I'm not sure what the advantage would be of allowingCstring
to contain an arbitraryPtr{Void}
And yes, it only constructs
Cstring
s... Any suggestion? The constructor was based on @stevengj's comment.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see why does this matter. In another word, I don't think it is necessary to make this
convert
method only defined for invalid pointers.reinterpret
already works and if you are adding another method to do the conversion you might as well make them the same. I don't think you will gain any safety by not allowing a non-NULL pointer to be converted toCstring
anyway.Much easier to inline, less code to write, less code to generate, in the cases the current version is inlined, less work for compiler to remove useless code.
Just replace
box(Cstring, p)
withbox(T, p)
as what you would usually do with a parametrized method.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, fine by me. I've pushed a commit removing the check and related test.