istringstream no honra base?

Estoy tratando de remediar algunos hallazgos de Coverity en valores contaminados debido al uso de atoi y atof . istringstream a un istringstream , pero no produce los resultados esperados para bases distintas a 10.

Si cambio a la base 16, ingrese 0xa y evite el iss.ignore(2); , entonces el resultado es 0:

 $ ./tt.exe 0xa X: 0 

Si cambio a la base 16, ingrese 0xa y utilizo el iss.ignore(2); , entonces el resultado es una excepción:

 $ ./tt.exe 0xa '0xa' is not a value 

Visité Referencia de CPP en istringstream según lo recomendado por @ πάντα, pero no discute una limitación en este contexto.

¿Alguna idea de lo que estoy haciendo mal? O, ¿cómo puedo hacer que esto funcione como se espera?


 $ cat tt.cxx #include  #include  #include  #include  using namespace std; template  T StringToValue(const std::string& str) { std::istringstream iss(str); T value; if (str.length() >= 2) { if (str[0] == '0' && (str[1] =='X' || str[1] =='x')) { iss.setf(std::ios_base::hex); iss.ignore(2); } } iss >> value; if (iss.fail()) throw runtime_error("'" + str +"' is not a value"); return value; } int main(int argc, char* argv[]) { try { int x = StringToValue(argc >= 2 ? argv[1] : "ZZZ..."); cout << "X: " << x << endl; } catch(const runtime_error& ex) { cerr << ex.what() << endl; return 1; } return 0; } 

Estás pensando demasiado en esto. Leer un valor en notación hexadecimal es fácil.

 #include  #include  #include  int main() { { int x = 0; std::istringstream is("0xa"); is >> std::hex >> x; assert(x == 10); } { int x = 0; std::istringstream is("a"); is >> std::hex >> x; assert(x == 10); } } 

( demostración en vivo )


En cualquier caso, puedo identificar dos problemas con su código.

1. Uso incorrecto de std::ios_base::setf

Estás reemplazando todo el conjunto de banderas de la transmisión con solo std::ios_base::hex . Las banderas no son solo para bases numéricas. Para hacerlo, necesita ocultar todo lo demás para evitar que se desestabilicen otras banderas no relacionadas, pero necesarias (no sé cuáles son):

 iss.setf(std::ios_base::hex, std::ios::basefield); 

Esta es la razón por la que iss >> std::hex es mucho más fácil.

¡También es la razón por la que debería haber construido un caso de prueba mínimo que consiste en nada más que una prueba de iss.setf antes de publicar!

2. lógica rota

El caso en el que la entrada es solo “a” omite esa statement por completo, ya que está condicionada a que los dos primeros caracteres sean “0x”.

Moverlo justo antes del iss >> value , lo haría.


Puede ver su código fijo aquí , pero, tal como se exploró al comienzo de mi respuesta, todo el asunto de "0x" conmutación al inicio es innecesario, por lo que la mayoría de su código solo puede eliminarse.