2012-07-26 15 views
6

Sto leggendo una stringa da un file in modo che sia sotto forma di un array char. Devo tokenize la stringa e salvare ogni token matrice char come valore esadecimale uint8_t in una matrice.Conversione da stringa di caratteri in un array di uint8_t?

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

Come posso convertire da starting a ending? Grazie.

+1

Ehi @Nirav, sembra che alcune risposte di seguito hanno contribuito a risolvere il problema. Se è così, sarebbe bello "accettare" la risposta che ti piace di più (con la casella di controllo a sinistra della risposta). Puoi (o sarai in grado di avere abbastanza reputazione) [votare su] (http://stackoverflow.com/privileges/vote-up) tutte le risposte utili. –

risposta

0

uint8_t è in genere non più di un typedef di un carattere non firmato. Se stai leggendo i caratteri da un file, dovresti essere in grado di leggerli in un array di char senza segno con la stessa facilità con un char array firmato, e un array di car unsigned è un array uint8_t.

+0

Si noti che @Nirav sta provando a convertire i caratteri ASCII che rappresentano le stringhe esadecimali nei valori interi. –

+0

Questo ti darebbe i valori ascii bue 0, x, 1-9, A-F non il valore dei caratteri esadecimali –

+0

Giusto, grazie per averlo indicato. – pinerd314159

0

mi piacerebbe provare qualcosa di simile:

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); 
} 

non prova esso ma si guarda bene a me ...

+0

Grazie, la funzione strtol era la parte che non riuscivo a capire! –

1

strtoul converte il testo in qualsiasi base che si sceglie in byte. Devi fare un po 'di lavoro per tagliare la stringa di input in singole cifre, oppure puoi convertire 32 o 64 bit alla volta.

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

Non significa niente, non memorizzano i dati in un uint8 come 'hex', si memorizzano i byte, è fino a come si (o il vostro debugger) interpreta i dati binari

+0

Bello! C'è una domanda di endianità per rispondere se si convertono 32 o 64 bit alla volta? –

+0

@rob - sì probabilmente! –

+0

Grazie, la funzione stroul ha funzionato –

2

Ecco un programma di lavoro completo. È basato sulla soluzione di Rob I, ma per risolvere diversi problemi è stato testato per funzionare.

#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, è possibile utilizzare std::stoi per questo:

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

Si può aggiungere la tua conversione da char set di { '0', '1', ... 'E', 'F'} per 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; 
} 

Allora sarà facile per convertire una stringa in a matrice:

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

credo che qualsiasi risposta canonica (wRTle note di taglie) comporterebbe alcune fasi distinte nella soluzione:

  • errore durante il controllo per l'ingresso valido
    • controllo Lunghezza e
    • contenuto dei dati di controllo di conversione
  • Elemento creazione
  • uscita

Dato th E l'utilità di tali conversioni, la soluzione dovrebbe probabilmente includere una certa flessibilità w.r.t. i tipi utilizzati e le impostazioni locali richieste.

Fin dall'inizio, data la data della richiesta di una "risposta più canonica" (circa agosto 2014), verrà applicato un uso liberale di C++ 11.

Una versione annotata del codice, con i tipi corrispondenti alla 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 versione del modello del codice aggiunge flessibilità;

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 funzione convert() può quindi essere basata sulla basic_convert() come segue:

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

Live sample.

0

Questa semplice soluzione dovrebbe funzionare per il vostro 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++; 
} 
Problemi correlati