सी ++/सीएलआई में, स्ट्रिंग्स की सरणी को देशी चार ** में बदलने का सबसे प्रभावी तरीका क्या है?
मैं यह कर रहा हूँ:
array<String^>^ tokenArray = gcnew array<String^> {"TokenONE", "TokenTWO"};
int numTokens = tokenArray->Length;
char** ptr = new char* [numTokens];
for(int i = 0; i < numTokens; i++)
{
// See: http://stackoverflow.com/questions/6596242/
array<Byte>^ encodedBytes = Text::Encoding::UTF8->GetBytes(tokenArray[i]);
pin_ptr<Byte> pinnedBytes = &encodedBytes[0];
ptr[i] = reinterpret_cast<char*>(pinnedBytes);
}
int myResult = someNativeFunction(ptr, numTokens);
delete ptr;
// ...
क्या होगा, अगर कुछ सुधार किया जाना चाहिए? क्या यह स्मृति प्रबंधन के दृष्टिकोण से ठीक है? जरूरत पड़ने पर मैं someNativeFunction
के मापदंडों को बदल सकता हूं।
धन्यवाद।
1 उत्तर
someNativeFunction()
को पास किए जाने से पहले पिन किए गए पॉइंटर्स के दायरे से बाहर जाने की समस्या के अलावा, कोड को बेहतर स्पष्टता के लिए सरल बनाया जा सकता है, खासकर यदि आप MSVC2008 या नए का उपयोग कर रहे हैं। एकल स्ट्रिंग को कैसे परिवर्तित किया जाए, इस बारे में जानकारी के लिए यह पृष्ठ देखें (सरणी तक विस्तार करना तुच्छ होना चाहिए) .
संपादित:
यदि आपको एएनएसआई स्ट्रिंग्स const char*
की आवश्यकता है तो एक प्रतिलिपि बनाना अनिवार्य है क्योंकि .NET स्ट्रिंग्स यूनिकोड (यूटीएफ -16) हैं। MSVC2008 और नए पर, आपका कोड इस प्रकार दिख सकता है:
#include <msclr/marshal.h>
using namespace msclr::interop;
marshal_context context;
array<String^>^ tokenArray = gcnew array<String^> {"TokenONE", "TokenTWO"};
char** tokensAsAnsi = new char* [tokenArray->Length];
for(int i = 0; i < tokenArray->Length; i++)
{
tokensAsAnsi[i] = context.marshal_as<const char*>(tokenArray[i]);
}
int myResult = someNativeFunction(ptr, tokensAsAnsi);
// The marshalled results are freed when context goes out of scope
delete[] tokensAsAnsi; // Please note you must use delete[] here!
यह आपके कोड नमूने के समान काम करता है लेकिन पॉइंटर पिनिंग और reinterpret_cast
-इंग की आवश्यकता के बिना।
यदि आप someNativeFunction()
में विस्तृत स्ट्रिंग const wchar_t*
से निपटने के इच्छुक हैं, तो आप सीधे (पिन किए गए) आंतरिक डेटा का उपयोग कर सकते हैं, हालांकि, आपको यह सुनिश्चित करना होगा कि someNativeFunction()
तक पॉइंटर्स पिन किए रहें। रिटर्न, जैसा कि टिप्पणियों में बताया गया है, जीसी प्रदर्शन को नकारात्मक रूप से प्रभावित कर सकता है।
यदि आप कई स्ट्रिंग्स को मार्शल करने वाले हैं और प्रदर्शन अत्यंत चिंता का विषय है, तो आप कर सकते हैं someNativeFunction()
को सब कुछ पास करने से पहले मार्शलिंग को कई थ्रेड्स में विभाजित करें। ऐसा करने से पहले, मैं यह देखने के लिए आपके आवेदन की रूपरेखा तैयार करने की अनुशंसा करता हूं कि क्या रूपांतरण वास्तव में एक बाधा है या कहीं और प्रयासों पर ध्यान केंद्रित करना बेहतर है।
#2 संपादित:
यूटीएफ -8 एन्कोडिंग में मूल स्ट्रिंग प्राप्त करने के लिए, आप अपने कोड के संशोधित संस्करण के साथ कर सकते हैं:
array<String^>^ tokenArray = gcnew array<String^> {"TokenONE", "TokenTWO"};
char** tokensAsUtf8 = new char* [tokenArray->Length];
for(int i = 0; i < tokenArray->Length; i++)
{
array<Byte>^ encodedBytes = Text::Encoding::UTF8->GetBytes(tokenArray[i]);
// Probably just using [0] is fine here
pin_ptr<Byte> pinnedBytes = &encodedBytes[encodedBytes->GetLowerBound(0)];
tokensAsUtf8[i] = new char[encodedBytes->Length + 1];
memcpy(
tokensAsUtf8[i],
reinterpret_cast<char*>(pinnedBytes),
encodedBytes->Length
);
// NULL-terminate the native string
tokensAsUtf8[i][encodedBytes->Length] = '\0';
}
int myResult = someNativeFunction(ptr, tokensAsAnsi);
for(int i = 0; i < tokenArray->Length; i++) delete[] tokensAsUtf8[i];
delete[] tokensAsUtf8;
यदि आप गति के बारे में चिंतित हैं, तो आप मूल स्ट्रिंग के लिए एक बड़ा बफर पूर्व-आवंटित कर सकते हैं (यदि आप जानते हैं कि केवल सीमित मात्रा होगी) या पूल स्टोरेज का उपयोग करें।
संपादित #3:(OG दोस्त) बस कुछ मामूली टाइपो को ठीक किया।
gcnew marshal_context
क्रिंग-प्रेरक है -- स्टैक सेमेन्टिक्स का उपयोग करें और कोई delete
आवश्यक नहीं है।
const char*
स्ट्रिंग UTF-8 एन्कोडेड हो तो आपका रास्ता ठीक है। आपको या तो वर्णों को किसी अन्य बफर में कॉपी करना होगा या डेटा को पिन करना होगा (उदाहरण के लिए पिन किए गए पॉइंटर्स को कंटेनर में डालकर) जब तक आप उनके साथ समाप्त नहीं कर लेते।
संबंधित सवाल
जुड़े हुए प्रश्न
नए सवाल
c++
C ++ एक सामान्य-प्रयोजन प्रोग्रामिंग भाषा है। यह मूल रूप से C के विस्तार के रूप में डिज़ाइन किया गया था और इसमें एक समान सिंटैक्स है, लेकिन यह अब पूरी तरह से अलग भाषा है। C ++ कंपाइलर के साथ संकलित कोड के बारे में प्रश्नों के लिए इस टैग का उपयोग करें। विशिष्ट मानक संशोधन [C ++ 11], [C ++ 14], [C ++ 17], [C ++ 20] या [C ++ 23], आदि से संबंधित प्रश्नों के लिए संस्करण-विशिष्ट टैग का उपयोग करें। ।
std::string
s का उपयोग करें।pin_ptr
उपयोग करने से पहले आपके दायरे से बाहर हो जाते हैं।someNativeFunction
पॉइंटर्स को अप्रारंभीकृत मेमोरी में पास कर रहे हैं, जिसके परिणामस्वरूप स्मृति भ्रष्टाचार होगा।pin_ptr
, उनकी सामग्री को अनपिन करते हुए,for
लूप के प्रत्येक पुनरावृत्ति के दायरे से बाहर हो जाते हैं, इसलिए जब तक आप प्रत्येकsomeNativeFunction
को कॉल करते हैंptr
का तत्व यादृच्छिक डेटा की ओर इशारा कर रहा है।