2010-10-08 6 views
2

Comment convertir std :: string en LPCSTR tout en préservant les caractères '\ 0'?convertir std :: string en LPCSTR avec '0' final ou '0'

Je veux utiliser le résultat sur OPENFILENAME.lpstrFilter qui nécessite que le filtre contienne '\ 0' comme délimiteurs.

std :: string.c_str() semble dépouiller et couper '\ 0'

Merci à l'avance!

==========================

(Comment puis-je ajouter correctement un commentaire aux réponses comme un message de réponse dans ? un forum)

Après avoir lu vos commentaires, je suis allé à vérifier cet extrait:

std::string filter = "Terrain Configuration (*.tcfg)\0*.tcfg\0\0"; 
const char* f1 = "Terrain Configuration (*.tcfg)\0*.tcfg\0\0"; 
const char* f2 = filter.c_str(); 
for(int i = 0; i < 50; i++) 
{ 
char c1 = *(f1 + i); // works 
char c2 = *(f2 + i); // doesn't work. beyond the first \0, it's garbage. 
} 

que je me trompe sur la façon dont c_str() ou travaux LPCSTR?

+0

Affichez http://msdn.microsoft.com/en-us/library/ ms646839% 28VS.85% 29.aspx: 'lpstrFilter: La dernière chaîne de la mémoire tampon doit être terminée par deux caractères NULL. Vous avez besoin de ** deux ** caractères NULL à la fin pour que ce paramètre fonctionne correctement; 'c_str()' par sa conception n'en a qu'un. – AshleysBrain

+0

Oui, je le sais. – Jake

Répondre

6

C_STR ne supprime pas les caractères NUL. L'erreur est probablement dans la façon dont vous construisez la chaîne STD ::.

+0

c_str NE supprime PAS la valeur null, mais soyez prudent, elle renvoie un pointeur qui appartient toujours à la classe de chaînes, vous devez donc vous assurer de copier le contenu –

+0

Veuillez voir la question éditée avec l'extrait. C'est dans le même champ d'application, n'est-ce pas? – Jake

+1

Quoi qu'il en soit, le point d'Alexander est que dans votre extrait le filtre std :: string n'est pas initialisé avec votre entrée complète car le constructeur s'arrêtera de lire au premier nul. Selon la réponse de Steve ci-dessous, vous devez utiliser le filtre 'std :: string (" Terrain Configuration (* .tcfg) \ 0 * .tcfg \ 0 \ 0 ", 40);' Je pense. – Rup

1

Cela dépend du cycle de vie de std :: string.

Par exemple, vous pouvez ajouter manuellement zéro borne:

std::string test("init"); 
test += '\0'; 

Cela provoque une longueur d'augmenter par un. Ou créez simplement une autre instance de std :: string avec zéro ajouté

2

Le length() de votre string est ce que vous devez utiliser pour vous assurer que tous les caractères sont inclus, à condition qu'il ait été correctement construit en premier lieu pour inclure les caractères \0 intégrés.

Pour un LPCSTR valide alors que cString est portée:

#include <boost/scoped_array.hpp> 
#include <string> 
#include <algorithm> 

string source("mystring"); 
boost::scoped_array<char> cString(new char[source.length() + 1]); 

std::copy(source.begin(), source.end(), cString.get()); 
cString[source.length()] = 0; 

LPCSTR rawStr = cString.get(); 

Sans scoped_array:

#include <string> 
#include <algorithm> 

string source("mystring"); 
LPSTR rawStr = new char[source.length() + 1]; 

std::copy(source.begin(), source.end(), rawStr); 
rawStr[source.length()] = 0; 

// do the work here 

delete[] rawStr; 

EDIT: Dans votre filter init, le constructeur de string ne comprend que jusqu'à des données du premier \0 char. Cela est logique - sinon comment ne pas arrêter de copier des données quand tout ce qu'il a en main est const char *? Essayez ceci avec:

const char f3[] = "Terrain Configuration (*.tcfg)\0*.tcfg\0\0"; 
std::string filter(f3, sizeof(f3)); 
+0

hmm ... Je pourrais copier un caractère à la fois, mais j'espère juste qu'il y a un moyen plus rapide. – Jake

+0

@Jake - 'std :: copy' supprime le besoin d'une boucle de copie bye by-byte. Si vous supprimez le 'scoped_array' ci-dessus, il pourrait être plus clair, juste nouveau directement dans' rawStr'. Voir éditer. –

5

De manière générale, std :: string gère correctement les caractères '\ 0'. Toutefois, lors de l'interfaçage avec const char *, il faut faire très attention.

Dans ce cas, le problème se produit déjà lors de la construction la chaîne avec:

std::string filter = "Terrain Configuration (*.tcfg)\0*.tcfg\0\0"; // wrong 

Ici vous construisez un std :: string à partir d'un const char *. Comme le constructeur ne sait pas combien de caractères utiliser pour construire la chaîne std ::, il s'arrête au premier '\ 0'.

On pourrait copier les caractères un par un soi-même, mais il y a une meilleure façon: utiliser le contructor qui nécessite deux itérateurs au tableau de caractères, une avec le début et un à la fin:

const char filter_[] = "Terrain Configuration (*.tcfg)\0*.tcfg\0\0"; 
std::string filter(filter_, filter_ + sizeof(filter_)); 

Cela semble horrible, mais j'espère que vous ne le ferez pas aussi souvent dans votre code.

Mise à jour: Ou avec les définitions de appropiate de commencer() et fin() modèles (selon le commentaire de James Kanze):

const char filter_[] = "Terrain Configuration (*.tcfg)\0*.tcfg\0\0"; 
std::string filter(begin(filter_), end(filter_)); 
+0

C'est sizeof (filter_) - 1 si la constante string a déjà –

+1

Désolé, pas utilisé pour cette interface: C'est sizeof (filter_) - 1 si la chaîne string déjà contient le double \ 0. L'initialisation d'un tableau avec une constante ajoute automatiquement un '\ 0'. Et bien sûr, cette utilisation de sizeof se casse lorsque le caractère est remplacé par wchar_t. Il serait préférable d'utiliser le modèle habituel fonctions begin (filter_), end (filter_), par exemple: \t std :: string (begin (filter_), end (filter_)); –

+0

@James Kanze: Merci de pointer les modèles begin() et end(), je ne les connaissais pas encore. – Sjoerd

Questions connexes