String in char ** konvertieren
-
ScyllaIllciz schrieb:
@topic: char* foo = NULL; std::string bar("Test"); foo = bar.c_str(); funky_c_func(&foo);Wie soll mir das weiter helfen, ich brauche doch char **foo bzw. char *foo[size]?
char** ist ein zeiger auf den zeiger eines char-array bzw ein zeiger auf einen zeiger.....
&foo ist char** in dem fall...
edit: Aussage korrigiert
rya.
-
Sofern du sicher bist, dass die Funktion nicht in den Strings rumschreibt, was mir angesichts der Signatur nicht gesichert scheint, könntest du Folgendes machen:
std::vector<char const *> ptr_list; ptr_list.reserve(list.size()); for(std::size_t i = 0; i < list.size(); ++i) { ptr_list.push_back(list[i].c_str()); } HANDLE h = foo(const_cast<char**>(&ptr_list[0]), ptr_list.size(), bar, baz);Das Ganze ist aber natürlich ein ziemlich dreckiger Hack.
-
seldon schrieb:
Sofern du sicher bist, dass die Funktion nicht in den Strings rumschreibt, was mir angesichts der Signatur nicht gesichert scheint, könntest du Folgendes machen:
std::vector<char const *> ptr_list; ptr_list.reserve(list.size()); for(std::size_t i = 0; i < list.size(); ++i) { ptr_list.push_back(list[i].c_str()); } HANDLE h = foo(const_cast<char**>(&ptr_list[0]), ptr_list.size(), bar, baz);Das Ganze ist aber natürlich ein ziemlich dreckiger Hack.
Und ich war gerade dabei ein extra Klassentemplate für 2D-C-Arrays mit überladenen Cast- und Dereferenzierungsoperatoren zu schreiben. Aber deines ist wesentlich weniger Schreibarbeit, deswegen lasse ich das Projekt mal halbfertig ruhen. Ich glaube mein Ansatz war viel zu kompliziert
.
-
Das soll heissen es geht nicht ohne cast?
-
ScyllaIllciz schrieb:
Das soll heissen es geht nicht ohne cast?
Irgendeine Art von Cast muss immer irgendwo stattfinden, wenn du nicht den Typen nehmen willst, der verlangt ist.
-
ScyllaIllciz schrieb:
Ich muss eine Lib einsetzten, die z.Bsp. so eine Funktion hat:
virtual HANDLE foo(/*[In]*/ char **ppszValues, /*[In]*/ unsigned long ulNumOfValues, /*[In]*/ unsigned long ulUpdateRate, /*[In]*/ HandlerCallback *pUpdateCallback = NULL,Wie kann ich den ersten Parameter übergeben ohne das ich das im C-Stil machen muss?
Was soll denn das /[In]/ ? -- Ich kann's mir denken, aber wenn der Parameter nur für die "Eingabe" ist, warum dann nicht doppel-const?
void nur_idioten_unterwegs(char const*const* values, ...);Die Antwort auf Deine Frage hängt natürlich auch davon ab, was Du eigentlich hast, also zB nen vector<string> ?
Wenn diese Bibliotheks-Funktion hält, was sie in den Kommentaren verspricht (dass sie nur lesend auf die Daten zugreift), könnte man auch einen const_cast verwenden, so dass da nichts kopiert werden muss.
vector<char*> meinezeiger; for (unsigned int i=0; i<ulCyc; i++) { meinezeiger.push_back(const_cast<char*>( variableList->at(i).toLocal8Bit().constData() )); } scheiss_funktion(&meinezeiger[0]);Ansonnsten könnte man auch alles hintereinander in einem vector<char> ablegen, wenn man das mit dem const_cast nicht machen will.
ScyllaIllciz schrieb:
Folgendes geht, ist aber nicht "schön":
std::vector<std::string> list; for (unsigned int i=0; i<ulCyc; i++) { list.push_back(variableList->at(i).toStdString()); } foo(reinterpret_cast<char**>(&list[0]),....)
Was ist Deine Definition von "geht"? Es lässt sich kompilieren, ja. Aber das wars auch schon.ScyllaIllciz schrieb:
Ich will new/delete und casts vermeiden. Gibt es Alternativen dazu?
Vektoren.
-
Nicht in standardkonformer Weise, ohne Kopien anzulegen. std::string garantiert weder, dass seine Daten an einem Stück gespeichert werden, noch, dass sie null-terminiert sind, dementsprechend ist alles, was &mein_string[0] heißt, von vorneherein ausgeschlossen. So bleibt c_str(), und das liefert dir einen char const , den du nicht ohne const_cast in einen char stopfen kannst.
-
seldon schrieb:
dass seine Daten an einem Stück gespeichert werden
Ich bin mir ziemlich sicher, dass zumindest dies irgendwo garantiert ist. Ich werde mal die Stelle suchen.
edit:
Solch eine Stelle gibt es anscheinend tatsächlich nicht. Wobei man hier aber wohl pragmatisch annehmen darf, dass jede vernünftige Implementierung dass trotzdem so macht.
-
@krümelkacker
Ich kann mir die Lib nicht auswählen, die ist so da und muss so verwendet werden (und kostet richtig Geld!)Das ist ein funktionierendes Beispiel (quick and dirty):
void MainWindow::on_pushButton_clicked() { QStringList list2; std::vector<std::string> list; for(int i=0; i<20; i++) { list2 << tr("Das ist %1").arg(i); list.push_back(list2[i].toStdString()); } if (writeMessage(reinterpret_cast<char**>(&list[0]), list.size())) QMessageBox::information(this, "Nachricht", "Hat funktioniert!!!"); } bool MainWindow::writeMessage(char **message, int size) { if (message) { for (int i=0; i<size; i++) qDebug() << "write Msg:" << message[i]; return true; } else return false; } }Ich werde aber die std::vector<const char*> Version wohl vorziehen, da hier "nur" const weg gecastet wird.
[edit]
Die Strings kommen später aus einer QStringList, deswegen ist die Beispiel mit drinnen
-
const char * strtocc(std::string s){return s.c_str();} // ... const char *chars[vec.size()]; transform(vec.begin(),vec.end(),chars,strtocc); foo(chars, ...)ohne die Funktion strtocc wäre es natürlich noch stilistischer...
-
@STLilist
hier wird aber auch ein const_cast benötigt
-
STLilist schrieb:
const char * strtocc(std::string s){return s.c_str();}Das erzeugt undefiniertes Verhalten. Meintest du
const char * strtocc(std::string const &s){return s.c_str();}?
Außerdem gibt es in C++ keine VLAs, also wird
const char *chars[vec.size()];nicht verlässlich funktionieren.
-
ScyllaIllciz schrieb:
Das ist ein funktionierendes Beispiel (quick and dirty):
void MainWindow::on_pushButton_clicked() { QStringList list2; std::vector<std::string> list; for(int i=0; i<20; i++) { list2 << tr("Das ist %1").arg(i); list.push_back(list2[i].toStdString()); } if (writeMessage(reinterpret_cast<char**>(&list[0]), list.size())) QMessageBox::information(this, "Nachricht", "Hat funktioniert!!!"); }

&list[0] ist vom Typ std::string* und Du reinterpretierst den Zeiger als char**. Das kann gar nicht funktionieren. string und char* haben nicht viel miteinander zu tun. string ist eine non-POD-Klasse, deren genauer Aufbau nicht festgelegt ist. Nicht einmal sizeof(char*)==sizeof(string) wird garantiert. Die Repräsentierung eines string-Objekts als Zeiger auf char zu interpretieren ist mit Abstand die schlechteste Idee, die ich je in C++ ausgedrückt gesehen habe.Mit welchem/r Compiler/Standardbibliothek soll dass denn angeblich funktionieren? Das kann ja nur funktionieren, wenn string zufällig so definiert wurde:
class string { char* meinzeiger; // <- erstes und einziges Datenelement public: ... };und selbst in diesem Fall ist ein Reinterpret-Cast Pfui, da string kein POD ist. Ich wüsste auch nicht, wo bei so einer Implementierung die Größe und die Kapazität des strings gespeichert wäre...
-
krümelkacker schrieb:
Das kann ja nur funktionieren, wenn string zufällig so definiert wurde:
class string { char* meinzeiger; // <- erstes und einziges Datenelement public: ... };und selbst in diesem Fall ist ein Reinterpret-Cast Pfui, da string kein POD ist. Ich wüsste auch nicht, wo bei so einer Implementierung die Größe und die Kapazität des strings gespeichert wäre...
falls dann rtti iwie aktiviert wird geht nichts mehr
oder etwa doch 
-
@krümelkackcker
läuft hier auf 'nem Mac mit gcc 4.2.1 und 'nem Linux mit gcc 4.4.2.
Aber Du hast natürlich Recht mit string*. Ich hatte gestern Abend viel ausprobiert und irgendwie ist das ein Überbleibsel gewesen!
-
ScyllaIllciz schrieb:
@krümelkackcker
läuft hier auf 'nem Mac mit gcc 4.2.1 und 'nem Linux mit gcc 4.4.2.
Aber Du hast natürlich Recht mit string*. Ich hatte gestern Abend viel ausprobiert und irgendwie ist das ein Überbleibsel gewesen!Du hast einfach Glück gehabt. Der C++ Standard definiert nicht, wie die string-Klasse genau implementiert werden soll. die libstdc++ Implementierung scheint äquivalent zu dem hier zu sein:
class string { char* anfang; // <-- einziges Datenelement public: ... }; int main() { string wtf = "hello!"; wtf.reserve(80); string s2 = wtf; char* p = reinterpret_cast<char*&>(wtf); }und im Speicher sieht das dann so aus:
p | V +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | 6 | 80 | 1 |'h'|'e'|'l'|'l'|'o'|'!'| 0 | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ (size) (capacity) (ref_count-1)Wie gesagt, Du hast Glück gehabt, dass in deinem Fall sizeof(string)==sizeof(char*) gilt und dass der char-Zeiger direkt auf das erste Zeichen der nullterminierten Zeichenkette zeigt. Aus der Dokumentation im Quelltext geht hervor, dass man das so gemacht hat, damit man schön im Debugger sehen kann, was für eine Zeichenkette das string-Objekt speichert.
Unter'm Microsoft Compiler ist sizeof(string) soweit ich weiß irgendwas bei 32 (wegen der "small string optimization").
kk