C#返回在函数内部使用stackalloc创建的指针 [英] C# Returning a pointer created with stackalloc inside a function

查看:131
本文介绍了C#返回在函数内部使用stackalloc创建的指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有与C ++代码交互的C#代码,该代码执行字符串操作.

I have C# code that interacts with C++ code, which performs operations with strings.

我在静态帮助器类中有这段代码:

I have this piece of code in a static helper class:

internal static unsafe byte* GetConstNullTerminated(string text, Encoding encoding)
{
    int charCount = text.Length;
    fixed (char* chars = text)
    {
        int byteCount = encoding.GetByteCount(chars, charCount);
        byte* bytes = stackalloc byte[byteCount + 1];
        encoding.GetBytes(chars, charCount, bytes, byteCount);
        *(bytes + byteCount) = 0;
        return bytes;
    }
}

如您所见,它返回一个指针,该指针指向用stackalloc关键字创建的字节.
但是,从C#规范18.8开始:

As you can see, it returns a pointer to the bytes created with the stackalloc keyword.
However from the C# Specifications 18.8:

在执行该函数成员时创建的所有堆栈分配的内存块都将在该函数成员返回时自动丢弃.

All stack allocated memory blocks created during the execution of a function member are automatically discarded when that function member returns.

这是否意味着该方法返回后指针实际上实际上是无效的?

Does it mean that the pointer is actually invalid as soon as the method returns?

该方法的当前用法:

byte* bytes = StringHelper.GetConstNullTerminated(value ?? string.Empty, Encoding);
DirectFunction(NativeMethods.SCI_SETTEXT, UIntPtr.Zero, (IntPtr) bytes);

应该将代码更改为

...
int byteCount = encoding.GetByteCount(chars, charCount);
byte[] byteArray = new byte[byteCount + 1];
fixed (byte* bytes = byteArray)
{
    encoding.GetBytes(chars, charCount, bytes, byteCount);
    *(bytes + byteCount) = 0;
}
return byteArray;

然后在返回的数组上再次使用fixed,将指针传递给DirectFunction方法?

And use fixed again on the array returned, to pass the pointer to the DirectFunction method?

我正在尝试尽量减少使用fixed的次数(包括GetByteCount()EncodingGetBytes()其他重载中的fixed语句).

I'm trying to minimise the number of fixed usages (including the fixed statements in other overloads of GetByteCount() and GetBytes() of Encoding).

tl; dr

  1. 方法返回后指针是否立即无效?在传递给DirectFunction()时是否无效?

如果是这样,使用最少的fixed语句来完成任务的最佳方法是什么?

If so, what is the best way to use the fewest fixed statements to achieve the task?

推荐答案

这是否意味着该方法返回后指针实际上实际上是无效的?

Does it mean that the pointer is actually invalid as soon as the method returns?

是的,从技术上讲,它是无效的-尽管几乎可以肯定不会检测到它.此情况是通过unsafe自行造成的.现在对该内存执行的任何操作都具有未定义的行为.您所做的任何事情,特别是调用方法,都可能会随机覆盖该内存-或不-取决于相对的堆栈帧大小和深度.

Yes, it is technically invalid - although it almost certainly won't be detected. This scenario is self-inflicted via unsafe. Any action on that memory now has undefined behavior. Anything you do, but in particular calling methods, may randomly overwrite that memory - or not - depending on the relative stack-frame sizes and depth.

这种情况特别是拟议的未来ref希望改变目标的一种情况,这意味着:允许stackalloc进入ref(而不是指针),并且编译器知道它是一个堆栈-引用ref或类似ref的类型,因此不允许ref返回该值.

This scenario is specifically one of the ones that the proposed future ref changes hope to target, meaning: allowing stackalloc into ref (rather than a pointer), with the compiler knowing that it is a stack-referring ref or ref-like type, and thus disallowing ref-return of that value.

最终,当您键入unsafe时,您说的是如果出现错误,我将承担全部责任".在这种情况下,确实是错误的.

Ultimately, the moment you type unsafe you're saying "I take full responsibility if this goes wrong". In this case, it is indeed wrong.

在离开该方法之前使用指针 是有效的,因此一种可行的方法可能是(假设您想要一个相当通用的API)以允许调用方传递一个委托或接口,该委托或接口指定调用者希望您使用指针的内容,即

It is valid to use the pointer before leaving the method, so one viable approach might be (assuming yo want a fairly general purpose API) to allow the caller to pass in a delegate or interface that specifies what the caller wants you to do with the pointer, i.e.

StringHelper.GetConstNullTerminated(value ?? string.Empty, Encoding,
    ptr => DirectFunction(NativeMethods.SCI_SETTEXT, UIntPtr.Zero, (IntPtr) ptr));

具有:

unsafe delegate void PointerAction(byte* ptr);
internal static unsafe void GetConstNullTerminated(string text, Encoding encoding,
    PointerAction action)
{
    int charCount = text.Length;
    fixed (char* chars = text)
    {
        int byteCount = encoding.GetByteCount(chars, charCount);
        byte* bytes = stackalloc byte[byteCount + 1];
        encoding.GetBytes(chars, charCount, bytes, byteCount);
        *(bytes + byteCount) = 0;
        action(bytes);
    }
}

还请注意,非常大的字符串可能会导致堆栈溢出.

Note also that very large strings may cause you to stack-overflow.

这篇关于C#返回在函数内部使用stackalloc创建的指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆