如何在 C# 中映射双 C 结构指针?
How to map double-C-struct-pointer in C#?
我对 libACL 进行了以下 C 调用:
extern int acl_get_entry(acl_t acl, int entry_id, acl_entry_t *entry_p);
extern int acl_get_permset(acl_entry_t entry_d, acl_permset_t *permset_p);
而且我已经将 typedef 追踪到
typedef struct __acl_permset_ext *acl_permset_t;
typedef struct __acl_entry_ext *acl_entry_t;
typedef struct __acl_ext *acl_t;
在/usr/include/acl/libacl.h 和/usr/include/sys/acl.h
所以除非我犯了一个错误,这意味着上面的本地调用等同于:
extern int acl_get_entry(__acl_ext *acl, int entry_id, __acl_entry_ext **entry_p);
extern int acl_get_permset(__acl_ext *entry_d, __acl_permset_ext **permset_p);
现在我对如何将它们映射到 C# 有点不知所措...
我首先想到我可以这样做:
// extern int acl_get_entry(acl_t acl, int entry_id, acl_entry_t *entry_p);
[SuppressUnmanagedCodeSecurity]
[DllImport("acl", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl, EntryPoint = "acl_get_entry")]
internal static extern int acl_get_entry(__acl_ext* acl, AclEntryConstants entry_id, ref __acl_entry_ext entry_p); // Double pointer, correct ???
这甚至有效,至少表面上如此。
但是当我对 acl_get_permset
做同样的事情时
// extern int acl_get_permset(acl_entry_t entry_d, acl_permset_t *permset_p);
[SuppressUnmanagedCodeSecurity]
[DllImport("acl", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl,
EntryPoint = "acl_get_permset")]
internal static extern int acl_get_permset(__acl_entry_ext* entry_d, __acl_permset_ext** permset_p); // double pointer ?
又名
internal static extern int acl_get_permset(__acl_entry_ext* entry_d, ref __acl_permset_ext permset_p); // double pointer ?
那就不行了...
我编写了以下 C 代码来检查:
int main()
{
// Get all the entries
acl_entry_t acl_entry_;
acl_permset_t permission_set;
acl_tag_t acl_kind_tag;
const char* _filename = "/root/Desktop/CppSharp.txt";
acl_t acl_file = acl_get_file(_filename, ACL_TYPE_ACCESS);
int found = acl_get_entry(acl_file, ACL_FIRST_ENTRY, &acl_entry_);
int a = acl_get_permset(acl_entry_, &permission_set);
int b = acl_get_tag_type(acl_entry_, &acl_kind_tag);
printf("a: %d; b: %d\n", a, b);
acl_entry new_acl;
new_acl.reading = ACL_GET_PERM(permission_set, ACL_READ);
new_acl.writing = ACL_GET_PERM(permission_set, ACL_WRITE);
new_acl.execution = ACL_GET_PERM(permission_set, ACL_EXECUTE);
return 0;
}
并且 returns a 和 b 的非 -1 值。
但是我的 C# 代码,它的作用完全相同(或者我认为是这样),到达 int found = 1
(就像 C 一样),但是它 returns -1 对于 a 和 b...
static unsafe void ReadACL()
{
string fileName = "/root/Desktop/CppSharp.txt";
global::acl.__acl_ext* acl_file = NativeMethods.acl_get_file(fileName, global::acl.acl_type_t.ACL_TYPE_ACCESS);
global::acl.__acl_entry_ext acl_entry_ = new global::acl.__acl_entry_ext();
int found = NativeMethods.acl_get_entry(acl_file, global::acl.AclEntryConstants.ACL_FIRST_ENTRY, ref acl_entry_);
System.Console.WriteLine(found);
global::acl.__acl_permset_ext permission_set;
acl_tag_t acl_kind_tag = acl_tag_t.ACL_UNDEFINED_TAG;
int a = NativeMethods.acl_get_permset(&acl_entry_, &permission_set);
global::acl.acl_tag_t tag_type = acl_tag_t.ACL_UNDEFINED_TAG;
int b = NativeMethods.acl_get_tag_type(&acl_entry_, &tag_type);
System.Console.WriteLine($"{a} {b}");
此外,最奇怪的是 - 我搜索了以下头文件:
/usr/include/acl/libacl.h
/usr/include/sys/acl.h
和 __acl_permset_ext
和 __acl_entry_ext
的整个 /usr/include
文件夹,但我需要 google 它们,因为它们无处定义...... C-编译器只使用指针,根本不需要结构?
此外,在手动执行之前,我尝试使用 CppSharp 自动创建绑定,但这些自动生成的绑定有完全相同的问题...
mono ./CppSharp.CLI.exe --arch=x64 --output=/home/username/RiderProjects/TestProject/TestProject/AUTOMAPPED/ /usr/include/acl/libacl.h /usr/include/sys/acl.h
我还注意到一件事:
通过双指针有什么意义?
就像
struct x;
function(ref &x)
恕我直言,这毫无意义,因为您通过引用传递了地址。
这些可能是数组吗?
喜欢
struct[] x;
function(ref x)
常量如下:
// #define ACL_UNDEFINED_ID ((id_t)-1)
// acl_check error codes
public enum acl_check_errors
: int
{
ACL_MULTI_ERROR = (0x1000), // multiple unique objects
ACL_DUPLICATE_ERROR = (0x2000), // duplicate Id's in entries
ACL_MISS_ERROR = (0x3000), // missing required entry
ACL_ENTRY_ERROR = (0x4000) // wrong entry type
}
// 23.2.2 acl_perm_t values
public enum acl_perm_t
: uint
{
ACL_READ = (0x04),
ACL_WRITE = (0x02),
ACL_EXECUTE = (0x01),
// ACL_ADD = (0x08),
// ACL_DELETE = (0x10),
}
// 23.2.5 acl_tag_t values
public enum acl_tag_t
: int
{
ACL_UNDEFINED_TAG = (0x00),
ACL_USER_OBJ = (0x01),
ACL_USER = (0x02),
ACL_GROUP_OBJ = (0x04),
ACL_GROUP = (0x08),
ACL_MASK = (0x10),
ACL_OTHER = (0x20)
}
public enum acl_type_t
: uint
{
ACL_TYPE_ACCESS = (0x8000),
ACL_TYPE_DEFAULT = (0x4000)
}
// 23.2.8 ACL Entry Constants
public enum AclEntryConstants
: int
{
ACL_FIRST_ENTRY = 0,
ACL_NEXT_ENTRY = 1,
}
这是我 google 一起构建的结构:
// https://kernel.googlesource.com/pub/scm/fs/ext2/xfstests-bld/+/301faaf37f99fc30105f261f23d44e2a0632ffc0/acl/libacl/libobj.h
// https://kernel.googlesource.com/pub/scm/fs/ext2/xfstests-bld/+/301faaf37f99fc30105f261f23d44e2a0632ffc0/acl/libacl/libobj.h
// https://kernel.googlesource.com/pub/scm/fs/ext2/xfstests-bld/+/301faaf37f99fc30105f261f23d44e2a0632ffc0/acl/libacl/libacl.h
// https://allstar.jhuapl.edu/repo/p1/amd64/acl/libacl.h
// https://kernel.googlesource.com/pub/scm/fs/ext2/xfstests-bld/+/301faaf37f99fc30105f261f23d44e2a0632ffc0/acl/libacl/libacl.h
// https://kernel.googlesource.com/pub/scm/fs/ext2/xfstests-bld/+/301faaf37f99fc30105f261f23d44e2a0632ffc0/acl/libacl/acl_get_fd.c
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public unsafe struct obj_prefix
{
public ulong p_magic;
public ulong p_flags;
}
// typedef struct __acl_permset_ext *acl_permset_t;
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public unsafe struct __acl_permset_ext
{
// permset_t s_perm; // typedef unsigned int permset_t;
public uint s_perm;
};
// typedef struct acl_permset_obj_tag acl_permset_obj;
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public unsafe struct acl_permset_obj_tag
{
public obj_prefix o_prefix;
public __acl_permset_ext i;
};
// #define __U32_TYPE unsigned int
// #define __ID_T_TYPE __U32_TYPE
// __STD_TYPE __ID_T_TYPE __id_t; /* General type for IDs. */
// typedef __id_t id_t;
/* qualifier object */
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public unsafe struct __qualifier_ext
{
//id_t q_id;
public uint q_id;
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public unsafe struct qualifier_obj_tag
{
public obj_prefix o_prefix;
public __qualifier_ext i;
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public unsafe struct acl_entry_obj_tag
{
public obj_prefix o_prefix;
public __acl_entry_ext i;
}
// typedef struct __acl_ext *acl_t;
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public unsafe struct __acl_ext
{
// typedef struct acl_entry_obj_tag acl_entry_obj;
// acl_entry_obj *a_prev, *a_next;
// acl_entry_obj *a_curr;
// acl_entry_obj *a_prealloc, *a_prealloc_end;
public acl_entry_obj_tag* a_prev;
public acl_entry_obj_tag* a_next;
public acl_entry_obj_tag* a_curr;
public acl_entry_obj_tag* a_prealloc;
public acl_entry_obj_tag* a_prealloc_end;
// size_t a_used; // typedef __SIZE_TYPE__ size_t;
public ulong a_used;
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public unsafe struct acl_obj_tag
{
public obj_prefix o_prefix;
public __acl_ext i;
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public unsafe struct __acl_entry
{
acl_tag_t e_tag;
// qualifier_obj e_id; // typedef struct qualifier_obj_tag qualifier_obj;
qualifier_obj_tag e_id;
// acl_permset_obj e_perm; //typedef struct acl_permset_obj_tag acl_permset_obj;
acl_permset_obj_tag e_perm;
}
// typedef struct __acl_entry_ext *acl_entry_t;
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public unsafe struct __acl_entry_ext
{
// acl_entry_obj *e_prev, *e_next; // typedef struct acl_entry_obj_tag acl_entry_obj;
public acl_entry_obj_tag* e_prev;
public acl_entry_obj_tag* e_next;
// acl_obj *e_container; // typedef struct acl_obj_tag acl_obj;
public acl_obj_tag* e_container;
public __acl_entry e_entry;
}
从 here 来看,这些 ACL 类型定义为:
struct __acl_ext;
struct __acl_entry_ext;
struct __acl_permset_ext;
typedef struct __acl_ext *acl_t;
typedef struct __acl_entry_ext *acl_entry_t;
typedef struct __acl_permset_ext *acl_permset_t;
我们被告知结构 __acl_ext
存在,但我们看不到它是如何定义的:我们不知道它有哪些字段。显然它在另一个(私有)头文件或源文件中被正确定义,但我们看不到那些:它们是私有的。
从表面上看,这似乎是一个问题:如果我们不知道它们有多大,或者它们的字段是如何布局的,我们如何使用这些结构?进一步看,您可以看到我们只与这些结构的 指针 交互:ACL 函数将返回一个指针,然后我们可以将其传递给其他 ACL 函数。我们永远不会期望自己取消引用指针。 ACL 代码当然知道指针指向什么,但这对我们是隐藏的。
这叫做opaque pointer。
(这可能是一个有用的策略。例如,它让 ACL 库在不破坏消费者的情况下更改结构的定义方式。它还阻止我们直接更改这些结构中的字段,这可能会破坏 ACL 库) .
所以。我们根本不应该尝试为这些结构定义 C# 类型:我们非常不打算这样做。不透明指针的 C# 类型是 IntPtr
,所以让我们使用它:
// extern int acl_get_entry(acl_t acl, int entry_id, acl_entry_t *entry_p);
[SuppressUnmanagedCodeSecurity]
[DllImport("acl", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acl_get_entry")]
internal static extern int acl_get_entry(IntPtr acl, AclEntryConstants entry_id, out IntPtr entry_p);
// extern int acl_get_permset(acl_entry_t entry_d, acl_permset_t *permset_p);
[SuppressUnmanagedCodeSecurity]
[DllImport("acl", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acl_get_permset")]
internal static extern int acl_get_permset(IntPtr entry_d, out IntPtr permset_p);
我们可以使用 ref
或 out
作为 IntPtr
。阅读文档,看起来 C 代码从不读取您传入的双指针的值:它只是将其用作将指针传回的一种方式。因此我们使用 out
.
我对 libACL 进行了以下 C 调用:
extern int acl_get_entry(acl_t acl, int entry_id, acl_entry_t *entry_p);
extern int acl_get_permset(acl_entry_t entry_d, acl_permset_t *permset_p);
而且我已经将 typedef 追踪到
typedef struct __acl_permset_ext *acl_permset_t;
typedef struct __acl_entry_ext *acl_entry_t;
typedef struct __acl_ext *acl_t;
在/usr/include/acl/libacl.h 和/usr/include/sys/acl.h
所以除非我犯了一个错误,这意味着上面的本地调用等同于:
extern int acl_get_entry(__acl_ext *acl, int entry_id, __acl_entry_ext **entry_p);
extern int acl_get_permset(__acl_ext *entry_d, __acl_permset_ext **permset_p);
现在我对如何将它们映射到 C# 有点不知所措...
我首先想到我可以这样做:
// extern int acl_get_entry(acl_t acl, int entry_id, acl_entry_t *entry_p);
[SuppressUnmanagedCodeSecurity]
[DllImport("acl", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl, EntryPoint = "acl_get_entry")]
internal static extern int acl_get_entry(__acl_ext* acl, AclEntryConstants entry_id, ref __acl_entry_ext entry_p); // Double pointer, correct ???
这甚至有效,至少表面上如此。
但是当我对 acl_get_permset
// extern int acl_get_permset(acl_entry_t entry_d, acl_permset_t *permset_p);
[SuppressUnmanagedCodeSecurity]
[DllImport("acl", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl,
EntryPoint = "acl_get_permset")]
internal static extern int acl_get_permset(__acl_entry_ext* entry_d, __acl_permset_ext** permset_p); // double pointer ?
又名
internal static extern int acl_get_permset(__acl_entry_ext* entry_d, ref __acl_permset_ext permset_p); // double pointer ?
那就不行了...
我编写了以下 C 代码来检查:
int main()
{
// Get all the entries
acl_entry_t acl_entry_;
acl_permset_t permission_set;
acl_tag_t acl_kind_tag;
const char* _filename = "/root/Desktop/CppSharp.txt";
acl_t acl_file = acl_get_file(_filename, ACL_TYPE_ACCESS);
int found = acl_get_entry(acl_file, ACL_FIRST_ENTRY, &acl_entry_);
int a = acl_get_permset(acl_entry_, &permission_set);
int b = acl_get_tag_type(acl_entry_, &acl_kind_tag);
printf("a: %d; b: %d\n", a, b);
acl_entry new_acl;
new_acl.reading = ACL_GET_PERM(permission_set, ACL_READ);
new_acl.writing = ACL_GET_PERM(permission_set, ACL_WRITE);
new_acl.execution = ACL_GET_PERM(permission_set, ACL_EXECUTE);
return 0;
}
并且 returns a 和 b 的非 -1 值。
但是我的 C# 代码,它的作用完全相同(或者我认为是这样),到达 int found = 1
(就像 C 一样),但是它 returns -1 对于 a 和 b...
static unsafe void ReadACL()
{
string fileName = "/root/Desktop/CppSharp.txt";
global::acl.__acl_ext* acl_file = NativeMethods.acl_get_file(fileName, global::acl.acl_type_t.ACL_TYPE_ACCESS);
global::acl.__acl_entry_ext acl_entry_ = new global::acl.__acl_entry_ext();
int found = NativeMethods.acl_get_entry(acl_file, global::acl.AclEntryConstants.ACL_FIRST_ENTRY, ref acl_entry_);
System.Console.WriteLine(found);
global::acl.__acl_permset_ext permission_set;
acl_tag_t acl_kind_tag = acl_tag_t.ACL_UNDEFINED_TAG;
int a = NativeMethods.acl_get_permset(&acl_entry_, &permission_set);
global::acl.acl_tag_t tag_type = acl_tag_t.ACL_UNDEFINED_TAG;
int b = NativeMethods.acl_get_tag_type(&acl_entry_, &tag_type);
System.Console.WriteLine($"{a} {b}");
此外,最奇怪的是 - 我搜索了以下头文件:
/usr/include/acl/libacl.h
/usr/include/sys/acl.h
和 __acl_permset_ext
和 __acl_entry_ext
的整个 /usr/include
文件夹,但我需要 google 它们,因为它们无处定义...... C-编译器只使用指针,根本不需要结构?
此外,在手动执行之前,我尝试使用 CppSharp 自动创建绑定,但这些自动生成的绑定有完全相同的问题...
mono ./CppSharp.CLI.exe --arch=x64 --output=/home/username/RiderProjects/TestProject/TestProject/AUTOMAPPED/ /usr/include/acl/libacl.h /usr/include/sys/acl.h
我还注意到一件事: 通过双指针有什么意义? 就像
struct x;
function(ref &x)
恕我直言,这毫无意义,因为您通过引用传递了地址。
这些可能是数组吗?
喜欢
struct[] x;
function(ref x)
常量如下:
// #define ACL_UNDEFINED_ID ((id_t)-1)
// acl_check error codes
public enum acl_check_errors
: int
{
ACL_MULTI_ERROR = (0x1000), // multiple unique objects
ACL_DUPLICATE_ERROR = (0x2000), // duplicate Id's in entries
ACL_MISS_ERROR = (0x3000), // missing required entry
ACL_ENTRY_ERROR = (0x4000) // wrong entry type
}
// 23.2.2 acl_perm_t values
public enum acl_perm_t
: uint
{
ACL_READ = (0x04),
ACL_WRITE = (0x02),
ACL_EXECUTE = (0x01),
// ACL_ADD = (0x08),
// ACL_DELETE = (0x10),
}
// 23.2.5 acl_tag_t values
public enum acl_tag_t
: int
{
ACL_UNDEFINED_TAG = (0x00),
ACL_USER_OBJ = (0x01),
ACL_USER = (0x02),
ACL_GROUP_OBJ = (0x04),
ACL_GROUP = (0x08),
ACL_MASK = (0x10),
ACL_OTHER = (0x20)
}
public enum acl_type_t
: uint
{
ACL_TYPE_ACCESS = (0x8000),
ACL_TYPE_DEFAULT = (0x4000)
}
// 23.2.8 ACL Entry Constants
public enum AclEntryConstants
: int
{
ACL_FIRST_ENTRY = 0,
ACL_NEXT_ENTRY = 1,
}
这是我 google 一起构建的结构:
// https://kernel.googlesource.com/pub/scm/fs/ext2/xfstests-bld/+/301faaf37f99fc30105f261f23d44e2a0632ffc0/acl/libacl/libobj.h
// https://kernel.googlesource.com/pub/scm/fs/ext2/xfstests-bld/+/301faaf37f99fc30105f261f23d44e2a0632ffc0/acl/libacl/libobj.h
// https://kernel.googlesource.com/pub/scm/fs/ext2/xfstests-bld/+/301faaf37f99fc30105f261f23d44e2a0632ffc0/acl/libacl/libacl.h
// https://allstar.jhuapl.edu/repo/p1/amd64/acl/libacl.h
// https://kernel.googlesource.com/pub/scm/fs/ext2/xfstests-bld/+/301faaf37f99fc30105f261f23d44e2a0632ffc0/acl/libacl/libacl.h
// https://kernel.googlesource.com/pub/scm/fs/ext2/xfstests-bld/+/301faaf37f99fc30105f261f23d44e2a0632ffc0/acl/libacl/acl_get_fd.c
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public unsafe struct obj_prefix
{
public ulong p_magic;
public ulong p_flags;
}
// typedef struct __acl_permset_ext *acl_permset_t;
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public unsafe struct __acl_permset_ext
{
// permset_t s_perm; // typedef unsigned int permset_t;
public uint s_perm;
};
// typedef struct acl_permset_obj_tag acl_permset_obj;
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public unsafe struct acl_permset_obj_tag
{
public obj_prefix o_prefix;
public __acl_permset_ext i;
};
// #define __U32_TYPE unsigned int
// #define __ID_T_TYPE __U32_TYPE
// __STD_TYPE __ID_T_TYPE __id_t; /* General type for IDs. */
// typedef __id_t id_t;
/* qualifier object */
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public unsafe struct __qualifier_ext
{
//id_t q_id;
public uint q_id;
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public unsafe struct qualifier_obj_tag
{
public obj_prefix o_prefix;
public __qualifier_ext i;
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public unsafe struct acl_entry_obj_tag
{
public obj_prefix o_prefix;
public __acl_entry_ext i;
}
// typedef struct __acl_ext *acl_t;
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public unsafe struct __acl_ext
{
// typedef struct acl_entry_obj_tag acl_entry_obj;
// acl_entry_obj *a_prev, *a_next;
// acl_entry_obj *a_curr;
// acl_entry_obj *a_prealloc, *a_prealloc_end;
public acl_entry_obj_tag* a_prev;
public acl_entry_obj_tag* a_next;
public acl_entry_obj_tag* a_curr;
public acl_entry_obj_tag* a_prealloc;
public acl_entry_obj_tag* a_prealloc_end;
// size_t a_used; // typedef __SIZE_TYPE__ size_t;
public ulong a_used;
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public unsafe struct acl_obj_tag
{
public obj_prefix o_prefix;
public __acl_ext i;
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public unsafe struct __acl_entry
{
acl_tag_t e_tag;
// qualifier_obj e_id; // typedef struct qualifier_obj_tag qualifier_obj;
qualifier_obj_tag e_id;
// acl_permset_obj e_perm; //typedef struct acl_permset_obj_tag acl_permset_obj;
acl_permset_obj_tag e_perm;
}
// typedef struct __acl_entry_ext *acl_entry_t;
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public unsafe struct __acl_entry_ext
{
// acl_entry_obj *e_prev, *e_next; // typedef struct acl_entry_obj_tag acl_entry_obj;
public acl_entry_obj_tag* e_prev;
public acl_entry_obj_tag* e_next;
// acl_obj *e_container; // typedef struct acl_obj_tag acl_obj;
public acl_obj_tag* e_container;
public __acl_entry e_entry;
}
从 here 来看,这些 ACL 类型定义为:
struct __acl_ext;
struct __acl_entry_ext;
struct __acl_permset_ext;
typedef struct __acl_ext *acl_t;
typedef struct __acl_entry_ext *acl_entry_t;
typedef struct __acl_permset_ext *acl_permset_t;
我们被告知结构 __acl_ext
存在,但我们看不到它是如何定义的:我们不知道它有哪些字段。显然它在另一个(私有)头文件或源文件中被正确定义,但我们看不到那些:它们是私有的。
从表面上看,这似乎是一个问题:如果我们不知道它们有多大,或者它们的字段是如何布局的,我们如何使用这些结构?进一步看,您可以看到我们只与这些结构的 指针 交互:ACL 函数将返回一个指针,然后我们可以将其传递给其他 ACL 函数。我们永远不会期望自己取消引用指针。 ACL 代码当然知道指针指向什么,但这对我们是隐藏的。
这叫做opaque pointer。
(这可能是一个有用的策略。例如,它让 ACL 库在不破坏消费者的情况下更改结构的定义方式。它还阻止我们直接更改这些结构中的字段,这可能会破坏 ACL 库) .
所以。我们根本不应该尝试为这些结构定义 C# 类型:我们非常不打算这样做。不透明指针的 C# 类型是 IntPtr
,所以让我们使用它:
// extern int acl_get_entry(acl_t acl, int entry_id, acl_entry_t *entry_p);
[SuppressUnmanagedCodeSecurity]
[DllImport("acl", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acl_get_entry")]
internal static extern int acl_get_entry(IntPtr acl, AclEntryConstants entry_id, out IntPtr entry_p);
// extern int acl_get_permset(acl_entry_t entry_d, acl_permset_t *permset_p);
[SuppressUnmanagedCodeSecurity]
[DllImport("acl", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acl_get_permset")]
internal static extern int acl_get_permset(IntPtr entry_d, out IntPtr permset_p);
我们可以使用 ref
或 out
作为 IntPtr
。阅读文档,看起来 C 代码从不读取您传入的双指针的值:它只是将其用作将指针传回的一种方式。因此我们使用 out
.