常数是否固定在C#中?
我在使用Borland C API的C#中工作,该API对字符串使用了大量字节指针。我一直需要将一些C#字符串作为(短寿命)字节*传递 我自然会假设const对象不会在堆上分配,而是直接存储在程序内存中,但我无法在任何文档中验证这一点 下面是我为生成指向常量字符串的指针所做的一个示例。这在测试中确实起到了预期的作用,我只是不确定它是否真的安全,或者它只是靠运气起作用常数是否固定在C#中?,c#,.net,garbage-collection,C#,.net,Garbage Collection,我在使用Borland C API的C#中工作,该API对字符串使用了大量字节指针。我一直需要将一些C#字符串作为(短寿命)字节*传递 我自然会假设const对象不会在堆上分配,而是直接存储在程序内存中,但我无法在任何文档中验证这一点 下面是我为生成指向常量字符串的指针所做的一个示例。这在测试中确实起到了预期的作用,我只是不确定它是否真的安全,或者它只是靠运气起作用 private const string pinnedStringGetWeight = "getWeight"; unsafe
private const string pinnedStringGetWeight = "getWeight";
unsafe public static byte* ExampleReturnWeightPtr(int serial)
{
fixed (byte* pGetWeight = ASCIIEncoding.ASCII.GetBytes(pinnedStringGetWeight))
return pGetWeight;
}
这个常数是真的被钉住了,还是有可能被移动
@克雷根: 以下是进口:
[DllImport("sidekick.dll", CallingConvention = CallingConvention.Winapi)]
public static extern int getValueByFunctionFromObject(int serial, int function, byte* debugCallString);
这是实际的功能。是的,它实际上需要一个静态函数指针:
private const int FUNC_GetWeight = 0x004243D0;
private const string pinnedStringGetWeight = "getWeight";
unsafe public static int getWeight(int serial)
{
fixed (byte* pGetWeight = ASCIIEncoding.ASCII.GetBytes(pinnedStringGetWeight))
return Core.getValueByFunctionFromObject(serial, FUNC_GetWeight, pGetWeight);
}
下面是我在模拟API时使用的另一种方法,使用静态结构,我也希望它是固定的。我希望能找到一种简化的方法
public byte* getObjVarString(int serial, byte* varName)
{
string varname = StringPointerUtils.GetAsciiString(varName);
string value = MockObjVarAttachments.GetString(serial, varname);
if (value == null)
return null;
return bytePtrFactory.MakePointerToTempString(value);
}
static UnsafeBytePointerFactoryStruct bytePtrFactory = new UnsafeBytePointerFactoryStruct();
private unsafe struct UnsafeBytePointerFactoryStruct
{
fixed byte _InvalidScriptClass[255];
fixed byte _ItemNotFound[255];
fixed byte _MiscBuffer[255];
public byte* InvalidScriptClass
{
get
{
fixed (byte* p = _InvalidScriptClass)
{
CopyNullString(p, "Failed to get script class");
return p;
}
}
}
public byte* ItemNotFound
{
get
{
fixed (byte* p = _ItemNotFound)
{
CopyNullString(p, "Item not found");
return p;
}
}
}
public byte* MakePointerToTempString(string text)
{
fixed (byte* p = _ItemNotFound)
{
CopyNullString(p, text);
return p;
}
}
private static void CopyNullString(byte* ptrDest, string text)
{
byte[] textBytes = ASCIIEncoding.ASCII.GetBytes(text);
fixed (byte* p = textBytes)
{
int i = 0;
while (*(p + i) != 0 && i < 254 && i < textBytes.Length)
{
*(ptrDest + i) = *(p + i);
i++;
}
*(ptrDest + i) = 0;
}
}
}
public byte*getObjVarString(int-serial,byte*varName)
{
string varname=StringPointerUtils.getascistring(varname);
string value=MockObjVarAttachments.GetString(serial,varname);
如果(值==null)
返回null;
返回bytePtrFactory.MakePointerToTempString(值);
}
静态UnsafeBytePointerFactoryStruct bytePtrFactory=新UnsafeBytePointerFactoryStruct();
私有不安全结构UnsafeBytePointerFactoryStruct
{
固定字节_invalidScript类[255];
固定字节_ItemNotFound[255];
固定字节_miscsbuffer[255];
公共字节*InvalidScript类
{
得到
{
已修复(字节*p=\u InvalidScript类)
{
CopyNullString(p,“无法获取脚本类”);
返回p;
}
}
}
公共字节*ItemNotFound
{
得到
{
已修复(字节*p=\u ItemNotFound)
{
CopyNullString(p,“未找到项”);
返回p;
}
}
}
公共字节*MakePointerToTempString(字符串文本)
{
已修复(字节*p=\u ItemNotFound)
{
CopyNullString(p,text);
返回p;
}
}
私有静态void CopyNullString(字节*ptrDest,字符串文本)
{
byte[]textBytes=ascienceoding.ASCII.GetBytes(text);
固定(字节*p=textBytes)
{
int i=0;
而(*(p+i)!=0&&i<254&&i
在这种情况下,常量的分配方式应该无关紧要,因为ascienceoding.ASCII.GetBytes()
返回一个新的字节数组(它不能返回常量的内部数组,因为它的编码不同(编辑:由于字符串是不可变的,所以希望无法获得指向字符串的内部数组的指针)). 但是,GC不会接触数组的保证只在固定的作用域接触数组时有效-换句话说,当函数返回时,内存不再固定。根据Kragans的注释,我研究了将字符串整理为字节指针的正确方法,现在我在问题中使用的第一个示例使用以下内容:
[DllImport("sidekick.dll", CallingConvention = CallingConvention.Winapi)]
public static extern int getValueByFunctionFromObject(int serial, int function, [MarshalAs(UnmanagedType.LPStr)]string debugCallString);
这不是将字符串封送到本机代码的方法-您可以发布一个(大概是P/Invoke)调用到C API的示例吗?我强烈怀疑常量字符串实际上是“固定”的,因为我不相信它们存储在垃圾收集堆上。这方面的一个证据是,常量字符串是使用“Ldstr”IL操作码加载的,常量字符串是作为方法体的一部分提供的。“fixed语句防止垃圾收集器重新定位可移动变量。fixed语句仅在不安全的上下文中允许使用。fixed还可用于创建固定大小的缓冲区。”———RunUO is so 2010:——)我很确定不能保证固定字符串常量(对于值类型常量,这个问题没有意义,所以我们这里只讨论字符串常量)。我认为主要的区别是,它们默认情况下会被占用,但占用并不意味着固定。只分配一些非托管内存如何?这一个肯定会被固定。这肯定回答了我的问题。完全没有回答。非常感谢。我返回的字节*一旦返回就完全不可靠,我很幸运。如果它回答了您的问题,您应该将此标记为答案。@Judah Himango:我不确定是否回答了常量是否固定的字面主题问题,即使这个答案完全足以满足关于我自己代码正确性的问题。谢谢您的编辑。一个好的观点:)如果我重新表述这个问题,我会问如何在程序集的整个过程中建立并修复指向字节[]的指针,在某种程度上,字符串的特殊性质使问题变得复杂。我现在走对了。再次感谢你的帮助。