本文介绍了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:

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

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?

推荐答案

是的,从技术上讲,它是无效的-尽管几乎可以肯定不会检测到它.此情况是通过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创建的指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-28 06:39