2012-07-26 24 views
6

Estoy leyendo una cadena de un archivo por lo que está en la forma de una matriz char. Necesito tokenizar la cadena y guardar cada token de matriz char como un valor hexadecimal uint8_t en una matriz.Convirtiendo de cadena de caracteres a una matriz de uint8_t?

char* starting = "001122AABBCC"; 
// ... 
uint8_t[] ending = {0x00,0x11,0x22,0xAA,0xBB,0xCC} 

¿Cómo puedo convertir de starting a ending? Gracias.

+1

Hey @Nirav, parece que algunas respuestas a continuación han ayudado a resolver su problema. Si ese es el caso, sería bueno "aceptar" la respuesta que más te guste (con la casilla de verificación a la izquierda de la respuesta). Puede (o podrá con suficiente reputación) [votar] (http://stackoverflow.com/privileges/vote-up) todas las respuestas útiles. –

Respuesta

0

uint8_t normalmente no es más que un typedef de un char sin signo. Si está leyendo caracteres de un archivo, debería poder leerlos en una matriz de caracteres sin signo con la misma facilidad que una matriz de caracteres firmada, y una matriz de caracteres sin signo es una matriz uint8_t.

+0

Tenga en cuenta que @Nirav está intentando convertir caracteres ASCII que representan cadenas hexagonales en los valores enteros. –

+0

Eso le daría los valores ascii buey 0, x, 1-9, A-F no el valor de los caracteres hexadecimales –

+0

Derecha, gracias por señalar eso. – pinerd314159

0

me gustaría probar algo como esto:

std::string starting_str = starting; 
uint8_t[] ending = new uint8_t[starting_str.length()/2]; 
for (int i = 0 ; i < starting_str.length() ; i+=2) { 
    std::string pair = starting_str.substr(i, i+2); 
    ending[i/2] = ::strtol(pair.c_str(), 0, 16); 
} 

no tomaron la prueba, pero se ve bien a mí ...

+0

¡Gracias, la función strtol fue la parte que no pude entender! –

1

strtoul será convertir el texto en cualquier base que elija en bytes. Tienes que trabajar un poco para cortar la cadena de entrada en dígitos individuales, o puedes convertir 32 o 64 bits a la vez.

ps uint8_t[] ending = {0x00,0x11,0x22,0xAA,0xBB,0xCC}

no significa nada, no va a almacenar los datos en un uint8 como 'hexagonal', que está almacenando bytes, es hasta qué usted (o su depurador) Interprètes los datos binarios

+0

¡Agradable! ¿Hay una pregunta de endianness para responder si se convierten 32 o 64 bits a la vez? –

+0

@rob - ¡sí, probablemente! –

+0

Gracias, la función stroul funcionó –

2

Aquí hay un programa de trabajo completo. Se basa en la solución de Rob I, pero se han probado varios problemas para que funcione.

#include <string> 
#include <stdio.h> 
#include <stdlib.h> 
#include <vector> 
#include <iostream> 


const char* starting = "001122AABBCC"; 
int main() 
{ 
    std::string starting_str = starting; 
    std::vector<unsigned char> ending; 
    ending.reserve(starting_str.size()); 
    for (int i = 0 ; i < starting_str.length() ; i+=2) { 
     std::string pair = starting_str.substr(i, 2); 
     ending.push_back(::strtol(pair.c_str(), 0, 16)); 
    } 

    for(int i=0; i<ending.size(); ++i) { 
     printf("0x%X\n", ending[i]); 
    } 

} 
1

con C++ 11, se puede utilizar para que std::stoi:

std::vector<uint8_t> convert(const std::string& s) 
{ 
    if (s.size() % 2 != 0) { 
     throw std::runtime_error("Bad size argument"); 
    } 
    std::vector<uint8_t> res; 
    res.reserve(s.size()/2); 
    for (std::size_t i = 0, size = s.size(); i != size; i += 2) { 
     std::size_t pos = 0; 
     res.push_back(std::stoi(s.substr(i, 2), &pos, 16)); 
     if (pos != 2) { 
      throw std::runtime_error("bad character in argument"); 
     } 
    } 
    return res; 
} 

Live example.

-1
uint8_t* ending = static_cast<uint8_t*>(starting); 
0

Usted puede añadir su propio conjunto de conversión de carbón { '0', '1', ... 'E', 'F'} para uint8_t:

uint8_t ctoa(char c) 
{ 
    if(c >= '0' && c <= '9') return c - '0'; 
    else if(c >= 'a' && c <= 'f') return 0xA + c - 'a'; 
    else if(c >= 'A' && c <= 'F') return 0xA + c - 'A'; 
    else return 0; 
} 

Entonces será fácil de convertir una cadena en serie a:

uint32_t endingSize = strlen(starting)/2; 
uint8_t* ending = new uint8_t[endingSize]; 

for(uint32_t i=0; i<endingSize; i++) 
{ 
    ending[i] = (ctoa(starting[i*2]) << 4) + ctoa(starting[i*2+1]); 
} 
1

creo que cualquier respuesta canónica (wRTlas notas de recompensas) implicarían algunas fases distintas en la solución:

  • Comprobación de errores de entrada válida
    • cheque Longitud y
    • Contenido de los datos de verificación de conversión
  • Elemento creación
  • salida

Given th Para la utilidad de tales conversiones, la solución probablemente debería incluir alguna flexibilidad w.r.t. los tipos que se usan y la configuración regional requerida.

Desde el principio, dada la fecha de la solicitud de una "respuesta más canónica" (circa agosto de 2014) se aplicará el uso liberal de C++ 11.

una versión anotada del código, con los tipos correspondientes a la OP:

std::vector<std::uint8_t> convert(std::string const& src) 
{ 
    // error check on the length 
    if ((src.length() % 2) != 0) { 
    throw std::invalid_argument("conversion error: input is not even length"); 
    } 

    auto ishex = [] (decltype(*src.begin()) c) { 
    return std::isxdigit(c, std::locale()); }; 

    // error check on the data contents 
    if (!std::all_of(std::begin(src), std::end(src), ishex)) { 
    throw std::invalid_argument("conversion error: input values are not not all xdigits"); 
    } 

    // allocate the result, initialised to 0 and size it to the correct length 
    std::vector<std::uint8_t> result(src.length()/2, 0); 

    // run the actual conversion  
    auto str = src.begin(); // track the location in the string 
    std::for_each(result.begin(), result.end(), [&str](decltype(*result.begin())& element) { 
    element = static_cast<std::uint8_t>(std::stoul(std::string(str, str + 2), nullptr, 16)); 
    std::advance(str, 2); // next two elements 
    }); 

    return result; 
} 

La versión de la plantilla del código añade flexibilidad;

template <typename Int /*= std::uint8_t*/, 
    typename Char = char, 
    typename Traits = std::char_traits<Char>, 
    typename Allocate = std::allocator<Char>, 
    typename Locale = std::locale> 
std::vector<Int> basic_convert(std::basic_string<Char, Traits, Allocate> const& src, Locale locale = Locale()) 
{ 
    using string_type = std::basic_string<Char, Traits, Allocate>; 

    auto ishex = [&locale] (decltype(*src.begin()) c) { 
     return std::isxdigit(c, locale); }; 

    if ((src.length() % 2) != 0) { 
    throw std::invalid_argument("conversion error: input is not even length"); 
    } 

    if (!std::all_of(std::begin(src), std::end(src), ishex)) { 
    throw std::invalid_argument("conversion error: input values are not not all xdigits"); 
    } 

    std::vector<Int> result(src.length()/2, 0); 

    auto str = std::begin(src); 
    std::for_each(std::begin(result), std::end(result), [&str](decltype(*std::begin(result))& element) { 
    element = static_cast<Int>(std::stoul(string_type(str, str + 2), nullptr, 16)); 
    std::advance(str, 2); 
    }); 

    return result; 
} 

La función convert() entonces se puede basar en la basic_convert() como sigue:

std::vector<std::uint8_t> convert(std::string const& src) 
{ 
    return basic_convert<std::uint8_t>(src, std::locale()); 
} 

Live sample.

0

Esta sencilla solución debe trabajar para su problema

char* starting = "001122AABBCC"; 
uint8_t ending[12]; 

// This algo will work for any size of starting 
// However, you have to make sure that the ending have enough space. 

int i=0; 
while (i<strlen(starting)) 
{ 
    // convert the character to string 
    char str[2] = "\0"; 
    str[0] = starting[i]; 

    // convert string to int base 16 
    ending[i]= (uint8_t)atoi(str,16); 

    i++; 
} 
Cuestiones relacionadas