2012-07-26 45 views
6

Tôi đang đọc một chuỗi từ một tệp sao cho nó ở dạng một mảng char. Tôi cần phải mã hóa chuỗi và lưu mỗi char mã thông báo mảng làm giá trị hex uint8_t trong một mảng.Chuyển đổi từ chuỗi char thành mảng uint8_t?

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

Làm cách nào để chuyển đổi từ starting thành ending? Cảm ơn.

+1

Hey @Nirav, nó trông giống như một vài câu trả lời dưới đây đã giúp giải quyết vấn đề của bạn. Nếu đó là trường hợp, nó sẽ được tốt đẹp để "chấp nhận" câu trả lời bạn thích nhất (với hộp kiểm bên trái của câu trả lời). Bạn có thể (hoặc sẽ có đủ danh tiếng) [vote up] (http://stackoverflow.com/privileges/vote-up) tất cả các câu trả lời hữu ích. –

Trả lời

0

uint8_t thường không nhiều hơn typedef của một thẻ chưa ký. Nếu bạn đang đọc các ký tự từ một tệp, bạn sẽ có thể đọc chúng thành mảng char chưa được ký hiệu dễ dàng như mảng char đã ký và mảng mảng unsigned char mảng uint8_t.

+0

Lưu ý rằng @Nirav đang cố gắng chuyển đổi các ký tự ASCII đại diện cho chuỗi hex thành các giá trị số nguyên. –

+0

Điều đó sẽ cung cấp cho bạn các giá trị ascii ox 0, x, 1-9, A-F không phải giá trị của các ký tự hex –

+0

Phải, cảm ơn bạn đã chỉ ra điều đó. – pinerd314159

0

Tôi muốn thử một cái gì đó như thế này:

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

Không kiểm tra nó nhưng có vẻ tốt với tôi ...

+0

Cảm ơn, chức năng strtol là một phần tôi không thể tìm ra! –

1

strtoul sẽ chuyển đổi văn bản trong bất kỳ cơ sở bạn chọn vào byte. Bạn phải thực hiện một ít công việc để cắt chuỗi đầu vào thành các chữ số riêng lẻ hoặc bạn có thể chuyển đổi 32 hoặc 64 bit mỗi lần.

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

Không có nghĩa là bất cứ điều gì, bạn không phải lưu trữ dữ liệu trong một uint8 là 'hex', bạn đang lưu trữ byte, đó là tối đa cách bạn (hoặc gỡ lỗi của bạn) interpretes dữ liệu nhị phân

+0

Tuyệt vời! Có một câu hỏi cuối cùng để trả lời nếu chuyển đổi 32 hoặc 64 bit tại một thời điểm? –

+0

@rob - có thể! –

+0

Cảm ơn, chức năng stroul đã làm việc –

2

Đây là một chương trình làm việc hoàn chỉnh. Nó dựa trên giải pháp của Rob I, nhưng sửa một số vấn đề đã được thử nghiệm để hoạt động.

#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

Với C++ 11, bạn có thể sử dụng std::stoi cho rằng:

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

Bạn có thể thêm chuyển đổi riêng của bạn từ bộ char { '0', '1', ... 'E', 'F'} để 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; 
} 

Sau đó, nó sẽ dễ dàng để chuyển đổi một chuỗi trong mảng:

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

tôi nghĩ rằng bất kỳ câu trả lời kinh điển (wrtcác nốt tiền thưởng) sẽ bao gồm một số giai đoạn khác nhau trong các giải pháp: kiểm tra

  • Lỗi cho đầu vào hợp lệ
    • kiểm tra chiều dài và
    • kiểm tra nội dung dữ liệu
  • Yếu tố chuyển đổi tạo
  • Output

Cho lần thứ e hữu ích của các chuyển đổi như vậy, giải pháp có lẽ nên bao gồm một số tính linh hoạt w.r.t. các loại đang được sử dụng và ngôn ngữ yêu cầu.

Ngay từ đầu, được đưa ra ngày yêu cầu "câu trả lời hợp lý hơn" (khoảng tháng 8 năm 2014) sẽ được áp dụng tự do C++ 11.

Một phiên bản chú thích của mã này, với các loại tương ứng với 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; 
} 

Mẫu phiên bản mã cho biết thêm tính linh hoạt;

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

Các convert() chức năng sau đó có thể được dựa trên basic_convert() như sau:

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

Live sample.

0

giải pháp đơn giản này sẽ làm việc cho vấn đề của bạn

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++; 
} 
Các vấn đề liên quan