Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在C中传递指向整数的指针#_C#_C_Interop_Pinvoke - Fatal编程技术网

C# 如何在C中传递指向整数的指针#

C# 如何在C中传递指向整数的指针#,c#,c,interop,pinvoke,C#,C,Interop,Pinvoke,我有一个带有签名的C API: int GetBuffer(char* buffer, int* maxSize) 在C中,我将这样称呼它: char buffer[4096]; int maxSize = 4096; GetBuffer(buffer, &maxSize); maxSize设置为缓冲区大小,并使用实际填充的大小进行设置 我需要从C#打电话给它。在“安全模式”下我该怎么做?拥有指针句柄根本不适合“安全模式”模型;如果资源不是由框架管理的,那么它是不安全的。您需要使用调

我有一个带有签名的C API:

int GetBuffer(char* buffer, int* maxSize)
在C中,我将这样称呼它:

char buffer[4096];
int maxSize = 4096;
GetBuffer(buffer, &maxSize);
maxSize设置为缓冲区大小,并使用实际填充的大小进行设置


我需要从C#打电话给它。在“安全模式”下我该怎么做?

拥有指针句柄根本不适合“安全模式”模型;如果资源不是由框架管理的,那么它是不安全的。

您需要使用调用的内容,并生成一个函数声明,从C#引用Dll中的C函数

但是,在将缓冲区传入/传出非托管代码时,必须非常小心。框架将为您处理一些事情,但您可能需要确保传入非托管调用的内存不会被垃圾收集器移动

[DllImport("Kernel32.dll", SetLastError=true)]
static extern Int32 GetBuffer(byte[] buffer,ref Int32 maxSize);
使用它:

byte[] myBuf = new myBuf[4096];
Int32 maxSize = myBuf.Length;

GetBuffer(myBuf, ref maxSize);

一种选择是简单地使用C#指针类型-这需要
不安全
块(或方法/类上的修饰符),并使用
/unsafe
编译:

[DllImport(...)]
static extern int GetBuffer(byte* buffer, ref int maxSize);
缓冲区可以用几种不同的方式分配。一种是使用固定堆数组:

fixed (byte* buffer = new byte[4096])
{
    int maxSize = buffer.Length;
    GetBuffer(buffer, ref maxSize);
}
另一种方法是使用
stackalloc
,但这仅适用于小型缓冲区:

byte* buffer = stackalloc byte[4096];
int maxSize = 4096;
GetBuffer(buffer, ref maxSize);
在性能和分配模式方面,这种特殊的方法实际上与您的C代码完全相同

另一个选择是对堆数组使用封送处理,并完全避免指针

[DllImport(...)]
static extern int GetBuffer([Out] byte[] buffer, ref int maxSize);

byte[] buffer = new byte[4096];
int maxSize = buffer.Length;
GetBuffer(buffer, ref maxSize);

这应该在没有不安全代码的情况下工作

extern int GetBuffer(IntPtr buffer, ref int bufSize);

// ...
byte[] buf = new byte[kBufSize];
GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned); // possibly expensive call 
IntPtr p = handle.AddrOfPinnedObject();
int size = buf.Length;
int ret = GetBuffer(p, ref size);
handle.Free();

一个简单而安全的选项是创建一个简单的类来包装该值或任何值,如以下代码所示:

public class Value<T> where T: struct 
{ 
    public static implicit operator T(Value<T> val) 
    { 
        return val.Value; 
    }

    private T _value;
 
    public Value(T value) 
    { 
        _value = value; 
    } 

    public Value() : this(default)
    { 
    }
 
    public T Value 
    { 
        get 
        { 
            return _value; 
        } 
        set 
        { 
            _value = value; 
        } 
    } 
 
    public override string ToString() 
    { 
        return _value.ToString(); 
    }
} 
公共类值,其中T:struct
{ 
公共静态隐式运算符T(值val)
{ 
返回值;
}
私人T_值;
公共价值(T值)
{ 
_价值=价值;
} 
公共值():此值(默认值)
{ 
}
公共价值
{ 
得到
{ 
返回_值;
} 
设置
{ 
_价值=价值;
} 
} 
公共重写字符串ToString()
{ 
返回_value.ToString();
}
} 

传递此类的实例而不是值本身的工作原理几乎与使用指针类似。

您还可以通过分配数组,然后使用GCHandle获取指向第一个元素()的指针来避免不安全的代码。
char
在C中在技术上是
sbyte
,在大多数情况下,但通常情况下,您会以
byte
的形式处理它们。我在上面的代码中将它改为
byte
。谢谢,这确实是我的错误(而且我不知道有哪个平台可以获得.NET,而且C
char
与C
byte
不匹配)。