C Interface
Base.@ccall
— Macro@ccall library.function_name(argvalue1::argtype1, ...)::returntype
@ccall function_name(argvalue1::argtype1, ...)::returntype
@ccall $function_pointer(argvalue1::argtype1, ...)::returntype
在 C 导出的共享库中调用一个函数,由 library.function_name
指定,其中 library
是一个字符串常量或字面量。可以省略库名,在这种情况下,function_name
在当前进程中解析。或者,@ccall
也可以用于调用一个函数指针 $function_pointer
,例如由 dlsym
返回的指针。
每个传递给 @ccall
的 argvalue
都会通过自动插入调用 unsafe_convert(argtype, cconvert(argtype, argvalue))
转换为相应的 argtype
。(有关详细信息,请参见 unsafe_convert
和 cconvert
的文档。)在大多数情况下,这仅仅导致调用 convert(argtype, argvalue)
。
示例
@ccall strlen(s::Cstring)::Csize_t
这调用 C 标准库函数:
size_t strlen(char *)
使用名为 s
的 Julia 变量。另请参见 ccall
。
支持可变参数,使用以下约定:
@ccall printf("%s = %d"::Cstring ; "foo"::Cstring, foo::Cint)::Cint
分号用于将必需参数(至少必须有一个)与可变参数分开。
使用外部库的示例:
# g_uri_escape_string 的 C 签名:
# char *g_uri_escape_string(const char *unescaped, const char *reserved_chars_allowed, gboolean allow_utf8);
const glib = "libglib-2.0"
@ccall glib.g_uri_escape_string(my_uri::Cstring, ":/"::Cstring, true::Cint)::Cstring
如果需要,字符串字面量也可以直接在函数名之前使用,例如 "libglib-2.0".g_uri_escape_string(...
ccall
— Keywordccall((function_name, library), returntype, (argtype1, ...), argvalue1, ...)
ccall(function_name, returntype, (argtype1, ...), argvalue1, ...)
ccall(function_pointer, returntype, (argtype1, ...), argvalue1, ...)
调用在 C 导出共享库中的函数,由元组 (function_name, library)
指定,其中每个组件可以是字符串或符号。除了指定库外,还可以使用 function_name
符号或字符串,这将在当前进程中解析。或者,ccall
也可以用于调用函数指针 function_pointer
,例如由 dlsym
返回的指针。
请注意,参数类型元组必须是字面量元组,而不是元组值变量或表达式。
每个传递给 ccall
的 argvalue
将通过自动插入调用 unsafe_convert(argtype, cconvert(argtype, argvalue))
转换为相应的 argtype
。(有关详细信息,请参见 unsafe_convert
和 cconvert
的文档。)在大多数情况下,这仅会导致对 convert(argtype, argvalue)
的调用。
Core.Intrinsics.cglobal
— Functioncglobal((symbol, library) [, type=Cvoid])
获取指向在 C 导出的共享库中的全局变量的指针,指定方式与 ccall
完全相同。如果未提供 Type
参数,则默认返回 Ptr{Cvoid}
。可以通过 unsafe_load
或 unsafe_store!
分别读取或写入这些值。
Base.@cfunction
— Macro@cfunction(callable, ReturnType, (ArgumentTypes...,)) -> Ptr{Cvoid}
@cfunction($callable, ReturnType, (ArgumentTypes...,)) -> CFunction
生成一个 C 可调用的函数指针,从给定类型签名的 Julia 函数 callable
。要将返回值传递给 ccall
,请在签名中使用参数类型 Ptr{Cvoid}
。
请注意,参数类型元组必须是字面量元组,而不是元组值变量或表达式(尽管它可以包含展开表达式)。并且这些参数将在编译时在全局作用域中进行评估(而不是推迟到运行时)。在函数参数前添加 '$' 会将其更改为在局部变量 callable
上创建一个运行时闭包(这并不支持所有架构)。
请参阅 manual section on ccall and cfunction usage。
示例
julia> function foo(x::Int, y::Int)
return x + y
end
julia> @cfunction(foo, Int, (Int, Int))
Ptr{Cvoid} @0x000000001b82fcd0
Base.CFunction
— TypeCFunction 结构体
用于处理从 @cfunction
返回值的垃圾回收句柄,当第一个参数用 '$' 注释时。像所有 cfunction
句柄一样,它应该作为 Ptr{Cvoid}
传递给 ccall
,并将在调用点自动转换为适当的类型。
请参见 @cfunction
。
Base.unsafe_convert
— Functionunsafe_convert(T, x)
将 x
转换为类型 T
的 C 参数,其中输入 x
必须是 cconvert(T, ...)
的返回值。
在需要 convert
将 Julia 对象转换为 Ptr
的情况下,应使用此函数来定义和执行该转换。
请小心确保在此函数的结果被使用期间,x
的 Julia 引用存在。因此,此函数的参数 x
不应是表达式,只应是变量名或字段引用。例如,x=a.b.c
是可接受的,但 x=[a,b,c]
则不可接受。
此函数的 unsafe
前缀表示,在此函数的 x
参数不再可被程序访问后使用此函数的结果可能会导致未定义行为,包括程序损坏或段错误,在任何后续时间。
另请参见 cconvert
Base.cconvert
— Functioncconvert(T,x)
将 x
转换为可以作为类型 T
传递给 C 代码的值,通常通过调用 convert(T, x)
实现。
在 x
不能安全地转换为 T
的情况下,与 convert
不同,cconvert
可能返回一个与 T
不同类型的对象,但该对象适合由 unsafe_convert
处理。此函数的结果在 unsafe_convert
不再需要之前应保持有效(以便于 GC)。这可以用于分配将被 ccall
访问的内存。如果需要分配多个对象,可以将这些对象的元组用作返回值。
convert
和 cconvert
都不应将 Julia 对象转换为 Ptr
。
Base.unsafe_load
— Functionunsafe_load(p::Ptr{T}, i::Integer=1)
unsafe_load(p::Ptr{T}, order::Symbol)
unsafe_load(p::Ptr{T}, i::Integer, order::Symbol)
从地址 p
开始的第 i
个元素(1 索引)加载类型 T
的值。这相当于 C 表达式 p[i-1]
。可以选择提供一个原子内存顺序。
此函数的 unsafe
前缀表示不会对指针 p
进行验证以确保其有效性。与 C 一样,程序员有责任确保在调用此函数时引用的内存未被释放或垃圾回收。错误的使用可能会导致程序段错误或返回垃圾答案。与 C 不同的是,解引用分配为不同类型的内存区域可能是有效的,只要这些类型是兼容的。
order
参数自 Julia 1.10 起可用。
另请参见: atomic
Base.unsafe_store!
— Functionunsafe_store!(p::Ptr{T}, x, i::Integer=1)
unsafe_store!(p::Ptr{T}, x, order::Symbol)
unsafe_store!(p::Ptr{T}, x, i::Integer, order::Symbol)
将类型为 T
的值存储到从 p
开始的第 i
个元素(1 索引)地址中。这相当于 C 表达式 p[i-1] = x
。可以选择提供一个原子内存顺序。
此函数的 unsafe
前缀表示不会对指针 p
进行验证以确保其有效性。与 C 一样,程序员有责任确保在调用此函数时引用的内存未被释放或垃圾回收。错误的使用可能会导致程序段错误。与 C 不同的是,只要类型兼容,将不同类型分配的内存区域存储可能是有效的。
order
参数自 Julia 1.10 起可用。
另请参见: atomic
Base.unsafe_modify!
— Functionunsafe_modify!(p::Ptr{T}, op, x, [order::Symbol]) -> Pair
这些操作原子地执行以获取和设置内存地址,应用函数 op
。如果硬件支持(例如,原子递增),这可能会优化为适当的硬件指令,否则其执行将类似于:
y = unsafe_load(p)
z = op(y, x)
unsafe_store!(p, z)
return y => z
此函数的 unsafe
前缀表示不会对指针 p
进行验证以确保其有效性。与 C 一样,程序员有责任确保在调用此函数时引用的内存未被释放或垃圾回收。错误的使用可能会导致程序段错误。
此函数至少需要 Julia 1.10。
另请参见: modifyproperty!
, atomic
Base.unsafe_replace!
— Functionunsafe_replace!(p::Ptr{T}, expected, desired,
[success_order::Symbol[, fail_order::Symbol=success_order]]) -> (; old, success::Bool)
这些操作原子地执行以获取并有条件地将内存地址设置为给定值。如果硬件支持,这可能会优化为适当的硬件指令,否则其执行将类似于:
y = unsafe_load(p, fail_order)
ok = y === expected
if ok
unsafe_store!(p, desired, success_order)
end
return (; old = y, success = ok)
此函数的 unsafe
前缀表示不会对指针 p
进行验证以确保其有效性。与 C 一样,程序员有责任确保在调用此函数时引用的内存未被释放或垃圾回收。不正确的使用可能会导致程序段错误。
此函数至少需要 Julia 1.10。
另请参见: replaceproperty!
, atomic
Base.unsafe_swap!
— Functionunsafe_swap!(p::Ptr{T}, x, [order::Symbol])
这些操作原子性地执行,以同时获取和设置内存地址。如果硬件支持,这可能会优化为适当的硬件指令,否则其执行将类似于:
y = unsafe_load(p)
unsafe_store!(p, x)
return y
此函数的 unsafe
前缀表示不会对指针 p
进行验证以确保其有效性。与 C 一样,程序员有责任确保在调用此函数时引用的内存未被释放或垃圾回收。不正确的使用可能会导致程序段错误。
此函数至少需要 Julia 1.10。
另请参见:swapproperty!
, atomic
Base.unsafe_copyto!
— Methodunsafe_copyto!(dest::Ptr{T}, src::Ptr{T}, N)
从源指针复制 N
个元素到目标指针,不进行任何检查。元素的大小由指针的类型决定。
该函数的 unsafe
前缀表示不会对指针 dest
和 src
进行验证,以确保它们是有效的。错误的使用可能会损坏或导致程序崩溃,方式与 C 语言相同。
Base.unsafe_copyto!
— Methodunsafe_copyto!(dest::Array, do, src::Array, so, N)
从源数组复制 N
个元素到目标数组,从源数组的线性索引 so
和目标数组的 do
开始(1 索引)。
此函数的 unsafe
前缀表示不会执行任何验证以确保 N 在任一数组中都是有效的。错误的使用可能会损坏或导致程序段错误,类似于 C 语言的情况。
Base.copyto!
— Functioncopyto!(B::AbstractMatrix, ir_dest::AbstractUnitRange, jr_dest::AbstractUnitRange,
tM::AbstractChar,
M::AbstractVecOrMat, ir_src::AbstractUnitRange, jr_src::AbstractUnitRange) -> B
高效地将矩阵 M
的元素复制到 B
,条件是字符参数 tM
如下:
tM | 目标 | 源 |
---|---|---|
'N' | B[ir_dest, jr_dest] | M[ir_src, jr_src] |
'T' | B[ir_dest, jr_dest] | transpose(M)[ir_src, jr_src] |
'C' | B[ir_dest, jr_dest] | adjoint(M)[ir_src, jr_src] |
元素 B[ir_dest, jr_dest]
会被覆盖。此外,索引范围参数必须满足 length(ir_dest) == length(ir_src)
和 length(jr_dest) == length(jr_src)
。
另见 copy_transpose!
和 copy_adjoint!
。
copyto!(dest::AbstractMatrix, src::UniformScaling)
将 UniformScaling
复制到矩阵上。
在 Julia 1.0 中,此方法仅支持方形目标矩阵。Julia 1.1 添加了对矩形矩阵的支持。
copyto!(dest, do, src, so, N)
从集合 src
中从线性索引 so
开始复制 N
个元素到数组 dest
中,从索引 do
开始。返回 dest
。
copyto!(dest::AbstractArray, src) -> dest
将集合 src
中的所有元素复制到数组 dest
,其长度必须大于或等于 src
的长度 n
。dest
的前 n
个元素将被覆盖,其他元素保持不变。
当任何被修改的参数与其他参数共享内存时,行为可能会出乎意料。
示例
julia> x = [1., 0., 3., 0., 5.];
julia> y = zeros(7);
julia> copyto!(y, x);
julia> y
7-element Vector{Float64}:
1.0
0.0
3.0
0.0
5.0
0.0
0.0
copyto!(dest, Rdest::CartesianIndices, src, Rsrc::CartesianIndices) -> dest
将 src
中范围为 Rsrc
的块复制到 dest
中范围为 Rdest
的块。两个区域的大小必须匹配。
示例
julia> A = zeros(5, 5);
julia> B = [1 2; 3 4];
julia> Ainds = CartesianIndices((2:3, 2:3));
julia> Binds = CartesianIndices(B);
julia> copyto!(A, Ainds, B, Binds)
5×5 Matrix{Float64}:
0.0 0.0 0.0 0.0 0.0
0.0 1.0 2.0 0.0 0.0
0.0 3.0 4.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
Base.pointer
— Functionpointer(array [, index])
获取数组或字符串的原生地址,选项上可以指定给定位置 index
。
此函数是“非安全”的。请小心确保在使用此指针的整个过程中,Julia 对 array
的引用存在。应使用 GC.@preserve
宏来保护 array
参数在给定代码块内不被垃圾回收。
调用 Ref(array[, index])
通常比此函数更可取,因为它保证了有效性。
Base.unsafe_wrap
— Methodunsafe_wrap(Array, pointer::Ptr{T}, dims; own = false)
在给定的 pointer
地址上将一个 Julia Array
对象包装在数据周围,而不进行复制。指针元素类型 T
决定了数组元素类型。dims
可以是一个整数(用于一维数组)或一个数组维度的元组。own
可选地指定 Julia 是否应当拥有内存,当数组不再被引用时调用 free
释放指针。
此函数被标记为“unsafe”,因为如果 pointer
不是有效的内存地址,且数据长度不匹配,则会崩溃。与 unsafe_load
和 unsafe_store!
不同,程序员还需确保底层数据不会通过两种不同元素类型的数组进行访问,这类似于 C 语言中的严格别名规则。
Base.pointer_from_objref
— Functionpointer_from_objref(x)
获取Julia对象的内存地址作为Ptr
。生成的Ptr
的存在不会保护对象不被垃圾回收,因此您必须确保在使用Ptr
的整个过程中对象保持被引用。
此函数不能在不可变对象上调用,因为它们没有稳定的内存地址。
Base.unsafe_pointer_to_objref
— Functionunsafe_pointer_to_objref(p::Ptr)
将 Ptr
转换为对象引用。假设指针指向一个有效的堆分配的 Julia 对象。如果不是这种情况,将导致未定义的行为,因此此函数被认为是“安全性不确定”,应谨慎使用。
Base.disable_sigint
— Functiondisable_sigint(f::Function)
在当前任务中执行函数时禁用 Ctrl-C 处理程序,以便调用可能会调用不安全的 julia 代码的外部代码。旨在使用 do
块语法调用,如下所示:
disable_sigint() do
# 不安全的中断代码
...
end
在工作线程上不需要这样做(Threads.threadid() != 1
),因为 InterruptException
只会发送到主线程。未调用 julia 代码或 julia 运行时的外部函数在执行期间会自动禁用 sigint。
Base.reenable_sigint
— Functionreenable_sigint(f::Function)
在执行函数期间重新启用 Ctrl-C 处理程序。暂时逆转 disable_sigint
的效果。
Base.exit_on_sigint
— Functionexit_on_sigint(on::Bool)
设置 julia 运行时的 exit_on_sigint
标志。如果为 false
,则 Ctrl-C (SIGINT) 可以在 try
块中捕获为 InterruptException
。这是 REPL 中的默认行为,通过 -e
和 -E
运行的任何代码,以及使用 -i
选项运行的 Julia 脚本。
如果为 true
,则 Ctrl-C 不会抛出 InterruptException
。在此事件发生时运行代码需要 atexit
。这是在没有 -i
选项运行的 Julia 脚本中的默认行为。
函数 exit_on_sigint
至少需要 Julia 1.5。
Base.systemerror
— Functionsystemerror(sysfunc[, errno::Cint=Libc.errno()])
systemerror(sysfunc, iftrue::Bool)
如果 iftrue
为 true
,则为 errno
引发一个 SystemError
,并使用描述性字符串 sysfunc
。
Base.windowserror
— Functionwindowserror(sysfunc[, code::UInt32=Libc.GetLastError()])
windowserror(sysfunc, iftrue::Bool)
类似于 systemerror
,但用于 Windows API 函数,这些函数使用 GetLastError
返回错误代码,而不是设置 errno
。
Core.Ptr
— TypePtr{T}
一个指向类型 T
数据的内存地址。然而,并不能保证该内存实际上是有效的,或者它确实表示指定类型的数据。
Core.Ref
— TypeRef{T}
一个安全引用类型为 T
的数据的对象。该类型保证指向有效的、由 Julia 分配的正确类型的内存。只要 Ref
本身被引用,底层数据就会受到垃圾收集器的保护,避免被释放。
在 Julia 中,Ref
对象通过 []
进行解引用(加载或存储)。
创建一个指向类型为 T
的值 x
的 Ref
通常写作 Ref(x)
。此外,对于创建指向容器(如 Array 或 Ptr)的内部指针,可以写作 Ref(a, i)
,用于创建对 a
的第 i
个元素的引用。
Ref{T}()
创建一个未初始化的类型为 T
的值的引用。对于位类型 T
,该值将是当前在分配的内存中存在的任何内容。对于非位类型 T
,引用将是未定义的,尝试解引用将导致错误,"UndefRefError: access to undefined reference"。
要检查一个 Ref
是否是未定义的引用,可以使用 isassigned(ref::RefValue)
。例如,如果 T
不是位类型,则 isassigned(Ref{T}())
为 false
。如果 T
是位类型,则 isassigned(Ref{T}())
将始终为 true。
当作为 ccall
参数传递(作为 Ptr
或 Ref
类型)时,Ref
对象将被转换为指向其引用的数据的本机指针。对于大多数 T
,或者当转换为 Ptr{Cvoid}
时,这是指向对象数据的指针。当 T
是 isbits
类型时,该值可以安全地被修改,否则修改将严格是未定义行为。
作为特例,设置 T = Any
将导致在转换为 Ptr{Any}
时创建指向引用本身的指针(如果 T 是不可变的,则为 jl_value_t const* const*
,否则为 jl_value_t *const *
)。当转换为 Ptr{Cvoid}
时,它仍将返回指向数据区域的指针,与任何其他 T
相同。
可以将 Ptr
的 C_NULL
实例传递给 ccall
的 Ref
参数以初始化它。
在广播中的使用
Ref
有时在广播中使用,以将引用的值视为标量。
示例
julia> r = Ref(5) # 创建一个具有初始值的 Ref
Base.RefValue{Int64}(5)
julia> r[] # 从 Ref 获取值
5
julia> r[] = 7 # 在 Ref 中存储新值
7
julia> r # Ref 现在包含 7
Base.RefValue{Int64}(7)
julia> isa.(Ref([1,2,3]), [Array, Dict, Int]) # 在广播期间将引用值视为标量
3-element BitVector:
1
0
0
julia> Ref{Function}() # 对非位类型 Function 的未定义引用
Base.RefValue{Function}(#undef)
julia> try
Ref{Function}()[] # 解引用未定义引用将导致错误
catch e
println(e)
end
UndefRefError()
julia> Ref{Int64}()[]; # 对位类型的引用如果未给出则引用一个未确定的值
julia> isassigned(Ref{Int64}()) # 对位类型的引用始终被赋值
true
Base.isassigned
— Methodisassigned(ref::RefValue) -> Bool
测试给定的 Ref
是否与一个值相关联。对于位类型对象的 Ref
,这总是为真。如果引用未定义,则返回 false
。
示例
julia> ref = Ref{Function}()
Base.RefValue{Function}(#undef)
julia> isassigned(ref)
false
julia> ref[] = (foobar(x) = x)
foobar (generic function with 1 method)
julia> isassigned(ref)
true
julia> isassigned(Ref{Int}())
true
Base.Cchar
— TypeCchar
等同于本地的 char
C 类型。
Base.Cuchar
— TypeCuchar
等同于原生的 unsigned char
C 类型 (UInt8
).
Base.Cshort
— TypeCshort
等同于本机的 signed short
C 类型 (Int16
).
Base.Cstring
— TypeCstring
由本机字符类型 Cchar
组成的 C 风格字符串。Cstring
是以 NUL 结尾的。有关由本机宽字符类型组成的 C 风格字符串,请参见 Cwstring
。有关与 C 的字符串互操作性的更多信息,请参见 manual。
Base.Cushort
— TypeCushort
等同于本地的 unsigned short
C 类型 (UInt16
).
Base.Cint
— TypeCint
等同于本地的 signed int
C 类型 (Int32
).
Base.Cuint
— TypeCuint
等同于本地的 unsigned int
C 类型 (UInt32
).
Base.Clong
— TypeClong
相当于原生的 signed long
C 类型。
Base.Culong
— TypeCulong
相当于本地的 unsigned long
C 类型。
Base.Clonglong
— TypeClonglong
等同于本地的 signed long long
C 类型 (Int64
).
Base.Culonglong
— TypeCulonglong
等同于本地的 unsigned long long
C 类型 (UInt64
).
Base.Cintmax_t
— TypeCintmax_t
等同于本地的 intmax_t
C 类型 (Int64
).
Base.Cuintmax_t
— TypeCuintmax_t
等同于本地的 uintmax_t
C 类型 (UInt64
).
Base.Csize_t
— TypeCsize_t
等同于本机的 size_t
C 类型(UInt
)。
Base.Cssize_t
— TypeCssize_t
等同于原生的 ssize_t
C 类型。
Base.Cptrdiff_t
— TypeCptrdiff_t
等同于本地的 ptrdiff_t
C 类型(Int
)。
Base.Cwchar_t
— TypeCwchar_t
等同于本地的 wchar_t
C 类型 (Int32
).
Base.Cwstring
— TypeCwstring
由本机宽字符类型 Cwchar_t
组成的 C 风格字符串。Cwstring
是以 NUL 结尾的。有关由本机字符类型组成的 C 风格字符串,请参见 Cstring
。有关与 C 的字符串互操作性的信息,请参见 manual。
Base.Cfloat
— TypeCfloat
等同于本地的 float
C 类型 (Float32
).
Base.Cdouble
— TypeCdouble
相当于本地的 double
C 类型 (Float64
).
LLVM Interface
Core.Intrinsics.llvmcall
— Functionllvmcall(fun_ir::String, returntype, Tuple{argtype1, ...}, argvalue1, ...)
llvmcall((mod_ir::String, entry_fn::String), returntype, Tuple{argtype1, ...}, argvalue1, ...)
llvmcall((mod_bc::Vector{UInt8}, entry_fn::String), returntype, Tuple{argtype1, ...}, argvalue1, ...)
调用第一个参数中提供的LLVM代码。可以通过几种方式指定此第一个参数:
- 作为一个字面字符串,表示函数级别的IR(类似于LLVM的
define
块),其中参数作为连续的未命名SSA变量(%0, %1等)可用; - 作为一个包含模块IR字符串和表示要调用的入口点函数名称的字符串的2元素元组;
- 作为一个2元素元组,但模块以
Vector{UInt8}
形式提供,包含位码。
请注意,与ccall
相反,参数类型必须指定为元组类型,而不是类型的元组。所有类型以及LLVM代码都应作为字面量指定,而不是变量或表达式(可能需要使用@eval
来生成这些字面量)。
不透明指针(写作ptr
)在LLVM代码中是不允许的。
有关用法示例,请参见test/llvmcall.jl
。