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 charSystem.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】:

以下代码不需要不安全的上下文(是的,它显示了有关stringGetHashCode 方法实现的内部螺栓和位,这表明它与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 结尾的字符串的指针?

char []到C#中的字符串[重复]

C DLL 中的 PInvoke char* 在 C# 中作为字符串处理。空字符问题

实验12——指针的基础应用2