C#中字符串中的char *指针
Posted
技术标签:
【中文标题】C#中字符串中的char *指针【英文标题】:char* pointer from string in C# 【发布时间】:2010-12-12 02:39:40 【问题描述】:是否可以在 C# 中为 string
变量获取 char*
?
我需要将路径字符串转换为 char*
以使用某些本机 win32 函数...
【问题讨论】:
【参考方案1】:你当然可以这样做:
string str = "my string";
unsafe
fixed (char* p = str)
// do some work
其中有一个操作符 (char*) 绑定到字符串对象。 但是,输出格式可能与底层 C 或其他格式不兼容......然而,这是解析字符串的一个很好的解决方案。 希望对阅读这篇文章的人有所帮助。
【讨论】:
这给出了一个指向System.Char
元素的指针,它对应于Win32的WCHAR*
,但问题要求char *
。
@TomBlodget char
是 System.Char
的类型别名。
@DrewNoakes 是的。我正在阅读问题中的char
,意思是本机字符。我现在的意图不是很清楚。
当 p 传递给本机函数时,这对我造成了访问冲突。【参考方案2】:
您可以将StringBuilder
作为char*
传递。
查看http://pinvoke.net,看看函数的签名是否已经存在。
【讨论】:
我授予这个答案,因为你基本上回答了我的问题,但似乎,至少对于我正在做的事情,所有需要的都是固定的(char* s = string)... 我用 SecureString(char*, int length) 试过这个,但 SecureString(sb, sb.Length) 或 SecureString((char*)sb, sb.Length) 都不起作用。说不能将 System.Text.StringBuilder 转换为 char*。 我试过这个,但我得到“无法从 'System.Text.StringBuilder' 转换为 'char*”【参考方案3】:以下代码不需要不安全的上下文(是的,它显示了有关string
的GetHashCode
方法实现的内部螺栓和位,这表明它与Java 中的方法不同,因为在C# 中的值哈希码没有被缓存,通常它表明 C# 字符串并不是像你可能被教导的那样最终是不可变的,不能处理 Fon Neiman):
using System;
using System.Runtime.InteropServices;
namespace Guess
class Program
static void Main(string[] args)
const string str = "ABC";
Console.WriteLine(str);
Console.WriteLine(str.GetHashCode());
var handle = GCHandle.Alloc(str, GCHandleType.Pinned);
try
Marshal.WriteInt16(handle.AddrOfPinnedObject(), 4, 'Z');
Console.WriteLine(str);
Console.WriteLine(str.GetHashCode());
finally
handle.Free();
【讨论】:
@zwcloud 完全错误的说法,答案是正确的,也是最有效和最不自以为是的(关于不安全的上下文)。答案正是它被要求做的事情。通过GCHandle.alloc
固定字符串的指针不会造成任何内存泄漏,除非您稍后在底层上下文中强制使用不正确的指针。 C# 中的整个指针/内存概念被认为是低级/高级主题,如果您使用指针,则意味着您了解整个概念并且基本上知道您在做什么。
关于引用的问答,这一点完全有效,但与上述问题无关,没有提到任何人都会存储指针。如果您要存储以供以后使用在 C# 中创建的字符串,那么显然您需要将其复制到 C 中,因为这将涉及在 C 中分配该字符串,这将允许 C 稍后将其释放。因此,这通常意味着您不能终生固定指针,也不能在 C# 中编组(创建)字符串的副本并将其存储在 C 中,因为 C 以后将无法释放它。跨度>
【参考方案4】:
这取决于你想做什么。当您通过 PInvoke 调用 Win32 函数时,您应该能够只传递 String 变量;该框架为您整理一切。如果您需要更复杂的东西,请查看Marshal.StringToHGlobalAnsi 和Marshal
类的其他方法。
【讨论】:
【参考方案5】:要结合已经给出的 2 个答案,这取决于您需要参数的方向。
如果函数只需要输入字符串,即const char *
,您可以使用System.String
(或普通string
)类型的参数。
如果函数填充一个字符串,即char * buffer, int bufferSize
,则可以传递一个System.Text.StringBuilder
。
在这两种情况下,(自动)编组都会为您进行必要的转换。
【讨论】:
已经感谢您的见解,但我在下面帖子的 cmets 中还有一些额外的评论...... 感谢您解释仅接受字符串的函数与构建字符串的函数之间的区别。每个人都一直在兜售StringBuilder
,但如果函数不打算修改字符串,那似乎就不对了。【参考方案6】:
您可以使用 Encoding.ASCII.GetBytes 从字符串中获取 byte[] 数组。 这可能可以使用 C# 中的固定语句转换为 char*。 (这固定分配的内存,不允许 gc 移动它 - 然后你可以创建一个指向它的指针)。
所以我的答案是肯定的,只有当你设法将 byte* 转换为 char* 时。 (在 C/C++ 中这不是问题,但我不太确定 C#)
PS> 如果我找到有关此文章的书签,我稍后会发布一些代码。我知道我在某个地方有它..
【讨论】:
您还应该考虑 Encoding.UTF8,因为它会保留所有 unicode 字符。 或者更确切地说,如果传递给原生 Win32 函数,最好使用 Encoding.Unicode(以及 C 端的 PWSTR)... 你必须先检查它们是否不是多字节的(我认为它们实际上是),因为这会使它“有点复杂”.. 有趣的是你应该提到“固定”。研究一个程序集(使用反射器)我在网上找到了一个依赖于与 Win32 实体交互的程序,我看到了一个采用字符串参数的方法。字符串发生的第一件事是固定的(char* path = (char*)strargument)...。 Char* 最终被分配给一个 win32 结构(WINTRUST_FILE_INFO.LPCWSTR 参数)。出于教育目的为自己尝试这个是行不通的(编译器说“无法将字符串转换为 char*”)代码将字符串直接分配给结构? 做了一些更多的研究......似乎在 C# 中执行以下操作是有效的: string test = "test";固定(char * p = test)..。让我感到震惊的是编译器通过生成以下内容来丑化它: private static unsafe void Main() string test = "test";固定 (char* CS$519$0000 = ((char*) test)) char* p = CS$519$0000;这让我觉得我需要能够找到将字符串转换为 char* 的方法谁会认为它会像 char* = string;【参考方案7】:就像其他一些帖子指出的那样,fixed (char* p = str)
与本机格式并不真正兼容,StringBuilder
也不能真正工作。这对我有用:
fixed (byte* p = Encoding.ASCII.GetBytes(str))
native_call((char*)p);
【讨论】:
以上是关于C#中字符串中的char *指针的主要内容,如果未能解决你的问题,请参考以下文章
在 C# String 构造函数 String(Char*) 中,为啥构造函数不期望指向字符数组的指针?
将 c++ dll 的 char 指针数组传递给 c# 字符串
如何在 C# 中编组指向一系列以 null 结尾的字符串的指针?