2009-11-01 6 views
26

Czy można uzyskać char* dla zmiennej string w języku C#?char * wskaźnik ze stringa w C#

muszę przekonwertować ciąg ścieżki do char* do korzystania z niektórych funkcji natywnej win32 ...

Odpowiedz

12

Możesz przekazać StringBuilder jako char*.

Spójrz na http://pinvoke.net, aby sprawdzić, czy podpis funkcji nie jest już dostępny.

+2

+1, Lub po prostu 'ciąg', jeśli jest to parametr wejściowy. – user7116

+3

Udzielam tej odpowiedzi, ponieważ zasadniczo odpowiedziałeś na moje pytanie, ale wydaje mi się, że przynajmniej dla tego, co robiłem, naprawiono (char * s = string) {...} – Kris

+17

Próbowałem tego z SecureStringiem (char *, int length) i ani SecureString (sb, sb.Length) ani SecureString ((char *) sb, sb.Length) działa. Says nie może konwertować System.Text.StringBuilder na char *. – Despertar

0

można uzyskać byte [] tablicy z łańcucha przy użyciu Encoding.ASCII.GetBytes. Jest to prawdopodobnie zamienny na char * za pomocą instrukcji fixed w języku C#. (Przypina przydzieloną pamięć, nie pozwalając gc jej przenieść - wtedy możesz zrobić wskaźnik do niej).

Tak więc moja odpowiedź brzmi "tak" tylko wtedy, gdy uda się przekonwertować bajt * na char *. (w C/C++ to nie byłby problem, ale nie jestem pewien co do C#)

PS> Wyślę trochę kodu później, jeśli znajdę zakładkę do artykułu na ten temat. Wiem, że mam to gdzieś ..

+0

należy również rozważyć Encoding.UTF8 jak zachowa wszystkie znaki unicode. – asveikau

+0

A raczej lepiej jest użyć Encoding.Unicode (i PWSTR na końcu C), jeśli przechodzisz do natywnej funkcji Win32 ... – asveikau

+0

Musisz najpierw sprawdzić, czy nie są one wielobajtowe (i myślę, że w rzeczywistości są), ponieważ komplikuje to "trochę" ... – kubal5003

4

To zależy od tego, co chcesz zrobić. Kiedy wywołasz funkcję Win32 przez PInvoke, powinieneś być w stanie po prostu przekazać zmienną String; struktura organizuje wszystko dla ciebie. Jeśli potrzebujesz czegoś bardziej skomplikowanego, spójrz na Marshal.StringToHGlobalAnsi i inne metody z klasy Marshal.

4

Aby połączyć 2 ankiety już podane, zależy to od kierunku, w jakim potrzebujesz dla danego parametru.

Jeśli funkcja wymaga tylko ciągu wejściowego, tj. const char *, można użyć argumentu typu System.String (lub zwykłego string).

Jeśli funkcja wypełnia ciąg, tj. char * buffer, int bufferSize, można przekazać System.Text.StringBuilder.

W obu przypadkach (auto-) Marshaling wykona dla Ciebie niezbędne konwersje.

+0

Dziękuję już za spostrzeżenia, ale mam kilka dodatkowych uwag w komentarzach do wpisu poniżej ... – Kris

+1

Dziękuję za wyjaśnienie różnicy między funkcją, która po prostu bierze ciąg, i taką, która buduje ciąg. Wszyscy po prostu zachwalali "StringBuilder", ale nie wydawało się to właściwe, jeśli funkcja nie będzie modyfikować napisu. – mpen

35

Cóż można na pewno to zrobić:

string str = "my string"; 

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

gdzie jest operatorem (char *) związanych z przedmiotem strun. Format wyjściowy może jednak nie być zgodny z podstawowym formatem C lub innym ... jest to jednak całkiem dobre rozwiązanie do analizy ciągu znaków. Mam nadzieję, że jest to pomocne dla każdego, kto przeczyta ten post.

+0

Daje to wskaźnik do elementów "System.Char", który odpowiada plikowi WCHAR * 'Win32, ale pytanie wymaga' char * '. –

4

Nie niebezpieczny kontekst wymagana jest następujący fragment kodu (i tak to pokazuje wewnętrzne śruby i bity o realizacji stringGetHashCode metoda pokazuje, że to różnica z jednym w Javie, ponieważ w C# wartość hashcode ISN” t buforowane i ogólnie to pokazuje, że C# struny nie są ostatecznie niezmienne jak ty może nauczono, nie może uporać się z 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

To jest niepoprawne, zobacz http://stackoverflow.com/a/10980174/3427520 – zwcloud

+2

@zwcloud ** Jest całkowicie niewłaściwa do stwierdzenia, odpowiedź jest poprawna i najbardziej wydajna i najmniej uparty (w odniesieniu do niebezpiecznego kontekstu) * *. Odpowiedź spełnia dokładnie to, o co została poproszona. Przypisanie wskaźnika ciągu do 'GCHandle.alloc' nie spowoduje żadnych wycieków pamięci, chyba że narzucimy niewłaściwe użycie wskaźników w późniejszym kontekście. Cała koncepcja wskaźnika/pamięci w języku C# jest uważana za temat niskiego poziomu/zaawansowany, a jeśli idziesz za pomocą wskaźników, oznacza to, że rozumiesz całą koncepcję i zasadniczo wiesz, co robisz. – Lu4

+2

W odniesieniu do zadanego pytania i odpowiedzi, punkt jest całkowicie poprawny, ale nie ma nic wspólnego z powyższym pytaniem, nie wspomniano, że ktokolwiek będzie przechowywać wskaźnik. Jeśli miałbyś przechowywać do późniejszego wykorzystania napis utworzony w języku C#, to oczywiście musiałbyś go skopiować w C, ponieważ wiązałby się z przydzieleniem tego ciągu w C, co pozwoliłoby C na późniejsze przydzielenie go. Oznacza to, że po prostu nie można przypiąć wskaźnika do końca życia ani dobrze jest marnować (tworzyć) kopię napisu w języku C# i przechowywać go w C, ponieważ C nie będzie w stanie zwolnić go później. – Lu4