std :: string zum schweben oder verdoppeln

98

Ich versuche zu konvertieren std::stringzu float/double. Ich habe es versucht:

std::string num = "0.6";
double temp = (double)atof(num.c_str());

Aber es gibt immer Null zurück. Irgendwelche anderen Möglichkeiten?

Max Frai
quelle
3
Widerstehen Sie dem Drang, etwas zu überarbeiten, das bereits vor einem Jahrzehnt herausgefunden wurde.
Haavee
1
Sind Sie sicher, dass Sie es richtig ausgeben? Es sollte nicht Null ergeben
Johannes Schaub - litb
1
Außerdem müssen Sie nicht atof wirken, es gibt bereits ein Double zurück.
AlbertoPL
Ich bin sicher. Der Debugger zeigt mir 0. Und das Ergebnis ist 0. Plattform: Linux.
Max Frai
12
Sind Sie sicher, dass Sie das richtige Gebietsschema installiert haben? versuchen Sie "0,6" oder setlocale (LC_NUMERIC, "C");
Johannes Schaub - litb

Antworten:

125
std::string num = "0.6";
double temp = ::atof(num.c_str());

Für mich ist es eine gültige C ++ - Syntax, um einen String in ein Double zu konvertieren.

Sie können dies mit dem Stringstream oder boost :: lexical_cast tun, aber diese sind mit einer Leistungsbeeinträchtigung verbunden.


Ahaha du hast ein Qt Projekt ...

QString winOpacity("0.6");
double temp = winOpacity.toDouble();

Zusätzlicher Hinweis:
Wenn die Eingabedaten a sind const char*, QByteArray::toDoublesind sie schneller.

TimW
quelle
Ich sehe keinen Grund, warum boost :: lexical_cast eine Leistungsbeeinträchtigung hätte (aber ein Stringstream ist sicherlich langsamer).
Zifre
7
boost :: lexical_cast wird gestreamt.
TimW
1
Man kann im Allgemeinen nicht sagen, dass sie mit einer Leistungsstrafe verbunden sind, denke ich. Überlegen Sie, was passiert, wenn Sie kurz davor eine Filmnummer haben. Der Benutzer müsste sehr schnell tippen (rly jon skeet like), um jemals zu bemerken, dass die Millisekunden lexical_cast langsamer sind :) Das heißt, ich glaube, es gibt Aufgaben, bei denen lexical_cast einfach zu viel Leistung saugt :)
Johannes Schaub - litb
3
Was macht das :: vor atof () für diese Lösung? Was muss es sein, um dort zu sein?
Sivabudh
4
@ShaChris Da ich sicherstellen möchte, dass ich die atof-Funktion aus dem globalen Namespace verwende.
TimW
104

Die Standardbibliothek (C ++ 11) bietet die gewünschte Funktionalität mit std::stod:

std::string  s  = "0.6"
std::wstring ws = "0.7"
double d  = std::stod(s);
double dw = std::stod(ws);

Im Allgemeinen für die meisten anderen Grundtypen siehe <string>. Es gibt auch einige neue Funktionen für C-Strings. Sehen<stdlib.h>

ManuelSchneid3r
quelle
4
Ich mag diese Lösung, aber es scheint, dass sie nur aus C ++ 11 stammt. Also nicht auf meinem SDK verfügbar.
pamplemousse_mk2
Es ist schön zu wissen, dass das C ++ - Standardkomitee dies hinzugefügt hat. ostringstreaman sich war einfach zu lang, um zu tippen, geschweige denn zu verwenden ..
Bobobobo
4
Für Floats (wie in der Frage gestellt, die ich bei Google durch Eingabe von "c ++ string to float" gefunden habe) sollte man std :: stof verwenden.
Étienne
1
Nur ein Hinweis, dass dies Ausnahmen auslösen kann: std :: invalid_argument (wenn die Konvertierung fehlgeschlagen ist) std :: out_of_range (wenn außerhalb des Bereichs)
Jason Doucette
2
Käufer aufgepasst, hängt vom aktuellen Gebietsschema ab.
nmr
29

Lexikalische Besetzung ist sehr nett.

#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>

using std::endl;
using std::cout;
using std::string;
using boost::lexical_cast;

int main() {
    string str = "0.6";
    double dub = lexical_cast<double>(str);
    cout << dub << endl;
}
Bill Lynch
quelle
Danke, es funktioniert. Aber es ist eine Frage für mich: Warum funktioniert mein Code nicht?
Max Frai
2
@Johannes Schaub: Basierend auf ADL könnte er genauso gut haben, dass die Verwendungsdefinitionen und das, was er tatsächlich verwendet, wahrscheinlich eine große Anzahl von Standardelementen in den Geltungsbereich bringen werden. Außerdem ist lexical_cast wahnsinnig langsam, also keine +1 von mir.
Eine nette Funktion von boost :: lexical_cast ist die Fehlerbehandlung. Wenn eine Konvertierung fehlschlägt, wird eine Ausnahme ausgelöst:try { ... boost::lexical_cast ... } catch (std::exception const& err) { //handle excpetion }
Semjon Mössinger
Um genauer zu sein, verwenden Sie catch ( boost::bad_lexical_cast const& err ), um die Ausnahme abzufangen.
Semjon Mössinger
14

Sie können std :: stringstream verwenden:

   #include <sstream>
   #include <string>
   template<typename T>
   T StringToNumber(const std::string& numberAsString)
   {
      T valor;

      std::stringstream stream(numberAsString);
      stream >> valor;
      if (stream.fail()) {
         std::runtime_error e(numberAsString);
         throw e;
      }
      return valor;
   }

Verwendung:

double number= StringToNumber<double>("0.6");
Edison Gustavo Muenz
quelle
Ähm, du denkst also, boost :: lexical_cast hat eine schreckliche Oberfläche, nicht wahr? Schau dir die Antwort von stefanB an! Boost macht das Gleiche.
Kirsche40
@ kirsche40 Scheint eine gute Alternative für Leute zu sein, die noch keine Abhängigkeiten mit Boost haben (das Verknüpfen mit Boost, nur um einen std :: string in Zahlen umzuwandeln, ist ein bisschen übertrieben!)
Jean-Philippe Jodoin
@ JEan-Phillippe Jodiun Ich antwortete auf einen jetzt gelöschten Kommentar, in dem jemand Boost empfohlen hat. Mir ist bewusst, dass Boost die meiste Zeit übertrieben ist. Übrigens ist die Verwendung von Boost seit einiger Zeit auf "neuere" Compiler beschränkt. Ältere Projekte können Boost nicht verwenden. Zum Beispiel hängt ASIO stark von C ++ 11-Funktionen wie std :: addressof ab, was es für C ++ 98 / C ++ 03-Compiler völlig wertlos macht. IMHO, als das Projekt begann, war es die Absicht von Boost, neue "standardisierte" Funktionen für ältere Compiler-Versionen bereitzustellen ... :-(
kirsche40
10

Ja, mit einer lexikalischen Besetzung. Verwenden Sie einen Stringstream und den Operator << oder verwenden Sie Boost, sie haben ihn bereits implementiert.

Ihre eigene Version könnte folgendermaßen aussehen:

template<typename to, typename from>to lexical_cast(from const &x) {
  std::stringstream os;
  to ret;

  os << x;
  os >> ret;

  return ret;  
}
DaClown
quelle
7

Sie können die lexikalische Besetzung verwenden:

#include <boost/lexical_cast.hpp>

string v("0.6");
double dd = boost::lexical_cast<double>(v);
cout << dd << endl;

Hinweis: boost :: lexical_cast löst eine Ausnahme aus, sodass Sie darauf vorbereitet sein sollten, damit umzugehen, wenn Sie einen ungültigen Wert übergeben. Versuchen Sie, eine Zeichenfolge ("xxx") zu übergeben.

stefanB
quelle
5

Wenn Sie nicht den gesamten Boost ziehen möchten, gehen Sie zu strtod(3)from <cstdlib>- es wird bereits ein Double zurückgegeben.

#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>

using namespace std;

int main()  {
    std::string  num = "0.6";
    double temp = ::strtod(num.c_str(), 0);

    cout << num << " " << temp << endl;
    return 0;
}

Ausgänge:

$ g++ -o s s.cc
$ ./s
0.6 0.6
$

Warum funktioniert atof () nicht ... auf welcher Plattform / auf welchem ​​Compiler bist du?

haavee
quelle
Die Verwendung eines Stringstreams würde keinen Boost erfordern
Jalf
Ihre Methode gibt auch Null zurück. Linux.
Max Frai
3

Ich hatte das gleiche Problem unter Linux

double s2f(string str)
{
 istringstream buffer(str);
 double temp;
 buffer >> temp;
 return temp;
}

Es klappt.

kenn
quelle
2
   double myAtof ( string &num){
      double tmp;
      sscanf ( num.c_str(), "%lf" , &tmp);
      return tmp;
   }
dpetek
quelle
1
Ungültige Antwort, woher wissen Sie, dass der in num gespeicherte Wert tatsächlich eine gültige Gleitkommazahl ist? Sie überprüfen nicht den Rückgabetyp von sscanf, scheint ein MS-Codierungsstil zu sein.
1

Diese Antwort sichert litb in Ihren Kommentaren. Ich habe den tiefen Verdacht, dass Sie das Ergebnis einfach nicht richtig anzeigen.

Mir war genau das Gleiche einmal passiert. Ich habe einen ganzen Tag lang versucht herauszufinden, warum ich einen schlechten Wert in ein 64-Bit-Int bekommen habe, nur um herauszufinden, dass printf das zweite Byte ignoriert. Sie können nicht einfach einen 64-Bit-Wert an printf übergeben, wie es ein int ist.

TED
quelle
Ich benutze printf nicht, um Ergebnisse zu sehen ... Und ich benutze diesen Wert, um die Deckkraft des Fensters festzulegen, und mein Fenster ist voll transparent, also ist der Wert 0.
Max Frai
1

Die C ++ 11-Methode besteht darin, std :: stod und std :: to_string zu verwenden. Beide funktionieren in Visual Studio 11.

BSalita
quelle
1

Warum atof()funktioniert die ursprüngliche Frage nicht? Die Tatsache, dass sie doppelt besetzt ist, macht mich misstrauisch. Der Code sollte nicht ohne kompiliert werden #include <stdlib.h>, aber wenn die Umwandlung hinzugefügt wurde, um eine Kompilierungswarnung zu lösen, atof()wird sie nicht korrekt deklariert. Wenn der Compiler davon ausgeht, dass atof()ein int zurückgegeben wird, löst das Casting die Konvertierungswarnung, führt jedoch nicht dazu, dass der Rückgabewert als double erkannt wird.

#include <stdlib.h>
#include <string>

... 
  std::string num = "0.6";
  double temp = atof(num.c_str());

sollte ohne Warnungen funktionieren.

Iain
quelle
0

Anstatt Boost in die Gleichung zu ziehen, können Sie Ihre Zeichenfolge (vorübergehend) als char[]und verwenden sprintf().

Aber wenn Sie Boost trotzdem verwenden, ist das natürlich kein allzu großes Problem.

Chris Tonkinson
quelle
0

Sie möchten Boost lexical_cast sowieso nicht für String <-> Gleitkomma. Diese Untergruppe von Anwendungsfällen ist die einzige Gruppe, für die Boost durchweg schlechter ist als die älteren Funktionen - und sie haben im Grunde alle ihre Fehler dort konzentriert, da ihre eigenen Leistungsergebnisse eine 20-25-fach langsamere Leistung zeigen als die Verwendung von sscanf und printf für solche Konvertierungen.

Google es selbst. boost :: lexical_cast kann etwa 50 Konvertierungen verarbeiten. Wenn Sie diejenigen mit Gleitkommazahlen ausschließen, ist dies genauso gut oder besser als die offensichtlichen Alternativen (mit dem zusätzlichen Vorteil, dass für alle diese Vorgänge eine einzige API vorhanden ist). Aber bringen Sie Schwimmer mit und es ist wie wenn die Titanic in Bezug auf die Leistung auf einen Eisberg trifft.

Die alten, dedizierten str-> double-Funktionen können alle 10000 Parses in etwa 30 ms (oder besser) durchführen. lexical_cast benötigt ungefähr 650 ms, um den gleichen Job zu erledigen.

Zack Yezek
quelle
Keine Quelle? Ich habe es selbst gegoogelt
Blake
0

Mein Problem:

  1. Gebietsschema unabhängige Zeichenfolge zu verdoppeln (Dezimaltrennzeichen immer '.')
  2. Fehlererkennung, wenn die Zeichenfolgenkonvertierung fehlschlägt

Meine Lösung (verwendet die Windows-Funktion _wcstod_l):

// string to convert. Note: decimal seperator is ',' here
std::wstring str = L"1,101";

// Use this for error detection
wchar_t* stopString;

// Create a locale for "C". Thus a '.' is expected as decimal separator
double dbl = _wcstod_l(str.c_str(), &stopString, _create_locale(LC_ALL, "C")); 

if (wcslen(stopString) != 0)
{
    // ... error handling ... we'll run into this because of the separator
}

HTH ... ich habe ziemlich lange gebraucht, um zu dieser Lösung zu gelangen. Und ich habe immer noch das Gefühl, dass ich nicht genug über String-Lokalisierung und so weiß ...

anhoppe
quelle