2009-11-01 147 views
26

Có thể nhận được char* cho biến số string trong C# không?char * con trỏ từ chuỗi trong C#

tôi cần phải chuyển đổi một chuỗi đường dẫn đến một char* cho việc sử dụng một số chức năng win32 bản địa ...

Trả lời

12

Bạn có thể chuyển số StringBuilder làm char*.

Hãy xem http://pinvoke.net để xem chữ ký cho hàm chưa có ở đó chưa.

+2

+1, Hoặc chỉ 'chuỗi' nếu nó là thông số đầu vào duy nhất. – user7116

+3

Tôi đang trả lời câu trả lời này vì bạn đã trả lời câu hỏi của mình nhưng có vẻ như, ít nhất cho những gì tôi đã làm tất cả những gì cần thiết đã được sửa (char * s = string) {...} – Kris

+17

Tôi đã thử với SecureString (char *, int chiều dài) và không SecureString (sb, sb.Length) hoặc SecureString ((char *) sb, sb.Length) hoạt động. Says không thể chuyển đổi System.Text.StringBuilder thành char *. – Despertar

0

Bạn có thể nhận mảng byte [] từ Encoding.ASCII.GetBytes chuỗi sử dụng. Điều này có thể chuyển đổi thành char * bằng cách sử dụng câu lệnh cố định trong C#. (Điều này ghim bộ nhớ phân bổ, không cho phép gc để di chuyển nó - sau đó bạn có thể làm cho một con trỏ đến nó).

Vì vậy, câu trả lời của tôi chỉ có nếu bạn quản lý chuyển đổi byte * thành char *. (trong C/C++ điều này sẽ không thành vấn đề, nhưng tôi không chắc chắn về C#)

PS> Tôi sẽ đăng một số mã sau nếu tôi tìm thấy một chỉ mục cho bài viết về điều này. Tôi biết tôi có nó ở đâu đó ..

+0

Bạn cũng nên xem xét mã hóa. – asveikau

+0

Hay đúng hơn, tốt hơn là sử dụng Encoding.Unicode (và PWSTR ở đầu C) nếu chuyển sang hàm Win32 riêng ... – asveikau

+0

Bạn phải kiểm tra trước nếu những thứ đó không phải là đa byte (và tôi nghĩ rằng thực tế chúng là), bởi vì điều này làm phức tạp nó một chút ".." – kubal5003

4

Điều đó tùy thuộc vào những gì bạn muốn làm. Khi bạn gọi một hàm Win32 thông qua PInvoke, bạn sẽ có thể chỉ cần vượt qua biến String; khuôn khổ marshals tất cả mọi thứ cho bạn. Nếu bạn cần một cái gì đó phức tạp hơn, hãy xem Marshal.StringToHGlobalAnsi và các phương pháp khác của lớp Marshal.

4

Để kết hợp 2 anwers đã được cung cấp, nó phụ thuộc vào hướng bạn cần cho tham số của bạn.

Nếu chức năng chỉ cần chuỗi đầu vào, nghĩa là const char *, bạn có thể sử dụng đối số loại System.String (hoặc đồng bằng string).

Nếu chức năng điền vào một chuỗi, tức là char * buffer, int bufferSize, bạn có thể chuyển một số System.Text.StringBuilder.

Trong cả hai trường hợp, Marshand sẽ tự động thực hiện các chuyển đổi cần thiết cho bạn.

+0

Cảm ơn đã cho những hiểu biết nhưng tôi có một số nhận xét bổ sung trong các ý kiến ​​của một bài viết dưới đây ... – Kris

+1

Cảm ơn bạn đã giải thích sự khác biệt giữa một hàm chỉ cần một chuỗi, và một trong đó xây dựng một chuỗi. Tất cả mọi người chỉ giữ touting 'StringBuilder' nhưng điều đó dường như không đúng nếu chức năng sẽ không sửa đổi chuỗi. – mpen

35

Vâng, bạn chắc chắn có thể làm điều này:

string str = "my string"; 

unsafe 
{ 
    fixed (char* p = str) 
    {    
     // do some work 
    } 
} 

nơi có một nhà điều hành (char *) liên kết với các đối tượng chuỗi. Tuy nhiên, định dạng đầu ra có thể không tương thích với định dạng C hoặc định dạng khác ... tuy nhiên đây là giải pháp tốt để phân tích chuỗi. Hy vọng nó hữu ích cho bất kỳ ai đọc bài đăng này.

+0

Điều này đưa ra một con trỏ tới các phần tử 'System.Char', tương ứng với' WCHAR * 'của Win32, nhưng câu hỏi yêu cầu' char * '. –

4

Không có bối cảnh không an toàn là cần thiết cho đoạn mã sau (và vâng nó cho thấy các bu lông và bit bên trong về việc thực hiện phương thức 'GetHashCode cho thấy sự khác biệt với một trong Java vì trong C# giá trị của hashcode isn' t lưu trữ và thường nó cho thấy rằng chuỗi C# không phải là cuối cùng không thay đổi như bạn có thể đã được dạy, không thể đối phó với 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(); 
      } 
     } 
    } 
} 
+0

Điều này không chính xác, hãy xem http://stackoverflow.com/a/10980174/3427520 – zwcloud

+2

@zwcloud ** Điều hoàn toàn sai trái của nó, câu trả lời là chính xác và hiệu quả nhất và ít được đề cập nhất (liên quan đến bối cảnh không an toàn) * *. Câu trả lời thực hiện chính xác những gì nó được yêu cầu làm. Ghim con trỏ chuỗi thông qua 'GCHandle.alloc' sẽ không tạo ra bất kỳ rò rỉ bộ nhớ nào trừ khi bạn sẽ sử dụng con trỏ không đúng cách sau này trong ngữ cảnh cơ bản. Toàn bộ con trỏ/khái niệm bộ nhớ trong C# được coi là chủ đề cấp thấp/nâng cao và nếu bạn đi với con trỏ nó có nghĩa là bạn hiểu toàn bộ khái niệm và về cơ bản biết những gì bạn đang làm. – Lu4

+2

Liên quan đến câu hỏi và câu trả lời được tham chiếu, điểm là hoàn toàn hợp lệ nhưng không có gì để làm cho câu hỏi trên, nó không được đề cập rằng bất cứ ai sẽ lưu trữ con trỏ. Nếu bạn đã lưu trữ để sử dụng sau này, một chuỗi được tạo trong C# rõ ràng là bạn sẽ cần phải sao chép nó trong C vì nó sẽ liên quan đến việc cấp phát chuỗi đó trong C, cho phép C có nó sau đó được deallocated. Vì vậy, nó thường có nghĩa là bạn không thể ghim con trỏ của bạn cho cuộc sống không phải là tốt để sắp xếp (tạo) một bản sao của chuỗi của bạn trong C# và có nó được lưu trữ trong C vì C sẽ không thể deallocate nó sau này. – Lu4